ofThread for computation


#1

hello
This is really a beginners programmer question on threads, so excuses for possible stupidity. I am working on some 2D slices of higher dimensional Julia sets using Clifford algebra and that demands a lot of computation. It is very easy to split the computational load into pieces (e.g. 4) by simply computing different parts of the image-surface separately. Then when the (4) threads have finished , I could use the data to draw in the fbo. I read the chapter on threads in the of-book and also what I could find here on the forum so I think I can write a class ComputeQuarterJulia which starts each thread. My question is How could I make sure that all threads are ready before I start to use the data for the fbo.
Thanks so much in advance
Vilbjørg
attached a slice of a 7D julia set


#2

Hi, use an ofThreadChannel. There’s an example in the examples folder. it will allow you to do what you need.
cheers


#3

Another useful resource is the chapter in OfBook. It seems like the example towards the top where its loading multiple images from an array of threads might be useful to you!


#4

Hi Thanks very much, guess I could not see the forest for all the trees. I think I must mess a bit around with the classes (having little affinity with c++) and then call .isThreadRunning() to make sure that all is computed.


#5

So yes, I have most gotten my head through the ofThreadChannel, The example is very good!. I have no problem loading pixel-data from the threads into sub-textures and drawing these as it is done in the example. But for some reason I have been messing around for a very long time trying to get the pixel data out from the side-thread to the main thread ( The reason for doing this is to merge the sub-images into one and save to disk) I have on the other hand no problem getting getting a bool from the side-thread, so perhaps it is some sort of a syntax problem . My best bet (in the main thread ) and its error is this:

error: invalid use of non-static member function
px4.setFromPixels(thread4.getPix, HWID , HHIG, OF_IMAGE_COLOR);

for whatever I have tried I get " invalid use of non-static member function "

Thanks very much in advance


#6

Well, the ofThreadChannel example passes pixel data back to the main thread. It need to be done this way so to upload the pixels to the GPU. Only the main thread can deal with openGL. can you post your code please?


#7

Thanks for looking at it… yes I believe it is not a problem with the threadChannel, I think I got that working fine. It is something with the pixels.setFromPixels in combination with getPixels from the threadClass ,

// from ThreadChannelTest.cpp


ofPixels & SpThread::getPix(){
	return pix;
}

bool & SpThread::getReady(){
	return ready;
}

void SpThread::setup(int quadrant, int p)
{
	prime = p;
	qNum = quadrant;	
}
	

void SpThread::computeNow(int s){

	compute.send(s);
}

void SpThread::transfer(){
	ready = false;
	// colVal is the ofThreadChannel to send pixels out of thread
	while(colVal.tryReceive(pix)){ 
		ready = true;
	}
	// if(ready)...here I can loadData to ofTexture and draw,
	// so I am sure that the pixels have arrived so far
}

//threadedFunction works

//--------------------------------------------
//------------------------------------------

//from ofApp.cpp

#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
	ofSetFrameRate(1);
	
	mainPixels.allocate(WID, HIG, OF_IMAGE_COLOR);
	mainTexture.allocate(mainPixels);
	
	px1.allocate(HWID, HHIG, OF_IMAGE_COLOR); // allocate 1/4 image
	px2.allocate(HWID, HHIG, OF_IMAGE_COLOR);
	px3.allocate(HWID, HHIG, OF_IMAGE_COLOR);
	px4.allocate(HWID, HHIG, OF_IMAGE_COLOR);
	
	thread1.setup(1, pselection[1]);
	thread2.setup(2, pselection[2]);
	thread3.setup(3, pselection[3]);
	thread4.setup(4, pselection[4]);

}

//--------------------------------------------------------------
void ofApp::update(){

	sCounter++;
	
	
	thread1.computeNow(sCounter);
	thread2.computeNow(sCounter);
	thread3.computeNow(sCounter);
	thread4.computeNow(sCounter);

}

//--------------------------------------------------------------
void ofApp::draw(){
	thread1.transfer();
	thread2.transfer();
	thread3.transfer();
	thread4.transfer();
	
	//This is the problem : tying to set pixels via getPix from each thread
	//error: invalid use of non-static member function
	px1.setFromPixels(thread1.getPix, HWID , HHIG, OF_IMAGE_COLOR);
	px2.setFromPixels(thread2.getPix, HWID , HHIG, OF_IMAGE_COLOR);
	px3.setFromPixels(thread3.getPix, HWID , HHIG, OF_IMAGE_COLOR);
	px4.setFromPixels(thread4.getPix, HWID , HHIG, OF_IMAGE_COLOR);
	// 
	
	px1.pasteInto(mainPixels, 0, 0);
	px2.pasteInto(mainPixels, HWID, 0);
	px3.pasteInto(mainPixels, 0, HHIG);
	px4.pasteInto(mainPixels, HWID, HHIG);
	// here I want to save to disk eventually
	mainTexture.loadData(mainPixels);
	mainTexture.draw(0, 0);
	
	r1 = thread1.getReady(); r2 = thread2.getReady(); r3 = thread3.getReady(); r4 = thread4.getReady();
	cout << r1 << " ; " << r2 << " ; " << r3 << " ; " << r4 << endl;
	

}


#8

in:

px1.setFromPixels(thread1.getPix, HWID , HHIG, OF_IMAGE_COLOR);

you have to actually call the function as:

px1.setFromPixels(thread1.getPix(), HWID , HHIG, OF_IMAGE_COLOR);

#9

OH yes


#10

actually I still get errors, something about converting the pixels from pointer to actual pixels I think:

note: no known conversion for argument 1 from ‘ofPixels’ to ‘const unsigned char*’

note: void ofPixels_::setFromPixels(const PixelType*, size_t, size_t, ofImageType) [with PixelType = unsigned char; size_t = long unsigned int]
void setFromPixels(const PixelType * newPixels,size_t w, size_t h, ofImageType type);

I was here before in search of a solution


#11

yes that function call is to fill an ofPixels from raw data, you don’t need to do that step, just:

thread1.getPix().pasteInto(mainPixels, 0, 0);
thread2.getPix().pasteInto(mainPixels, HWID, 0);
......

#12

yes yes , compiles and runs,