Click to See Complete Forum and Search --> : multithreading on OSX


memoid
June 21st, 2008, 09:51 AM
Hi all, I have a query about multithreading. What I would like to do is, at the start of my main update() function, start a couple of threads in parallel, once they are all complete carry on with my main update function.


void update() {
thread1->update(); // fluid solver
thread2->update(); // particle system
thread3->update(); // camera1 optical flow
thread4->update(); // camera2 optical flow
// all of the above threads have their own data and work independantly

etc.
.
.. wait till all the above threads are done.
.. once they are done, feed the data from each of them into other ones
.. e.g. fluid velocity info is added to particle systems reedy for next frame's update
.. e.g. camera optical flow data is fed into fluid solver, ready for next frame's update

render all
}


I am having trouble getting this working the way I want. I don't want my threads to loop continuously independent of my main update loop, I want them all to start at the beginning of my update loop, and then once they are all finished, feed the data around, then render, then repeat.

I tried creating a thread every update loop which runs only once (no while() in the function) - it works and behaves fine for a few minutes, then the threads just stop being created - no crash or hang, just no updates from threads. I also tried using an infinte while() but with a flag that determined whether the code ran that frame or not, and only set that flag at the beginning of the main update loop (code for this below) - that one is very stable, but behaviour was weird, I think the thread updates weren't being called when I wanted them to.

I've read a lot of documentation on multithreading in general and all the pthread commands. I understand the fundamentals of protecting data and all that.. but I'm just lacking a lot of experience and strategy .. so any suggestions welcome!


This is my thread class I'm using which has the infinite loop in the threaded function, but only runs the update function if the flag is set. I initialize the flag at the beginning of each main update with thread1->runOnce(); thread2->runOnce(); etc.... but it doesn't run smoothly.



#include "ofxThread.h"

class MSAThread : public ofxThread {

bool bHasRunThisFrame;
bool bAutoLoop;
int interval;

public:

// create the thread, if autoLoop is true, start running straight away and loop,
// otherwise wait for the runOnce command
void start(int frameRate = 30, bool initAutoLoop = false){
interval = 1000/frameRate;
bAutoLoop = initAutoLoop;
if(!bAutoLoop) bHasRunThisFrame = true; // don't run straight away
startThread(true, false); // blocking, verbose
}

// run the update function once in another thread
void runOnce() {
if(lock()) {
bAutoLoop = false;
bHasRunThisFrame = false;
unlock();
}
}

// run the update function in another thread
void threadedFunction() {
while(isThreadRunning()) {
if( lock() ){
if(bAutoLoop || !bHasRunThisFrame) {
update();
bHasRunThisFrame = true;
unlock();
ofSleepMillis(interval);
} else {
unlock();
}
}
}
}

// main thread waits for the update function to finish
void waitForFinish() { if(lock()) { unlock(); } }

// this is the function that gets overvidden
virtual void update() = 0;
};


and it's based on this OpenFrameworks class:

class ofxThread{

public:
ofxThread();
virtual ~ofxThread();
bool isThreadRunning();
void startThread(bool _blocking = true, bool _verbose = true);
bool lock();
bool unlock();
void stopThread();

protected:

//-------------------------------------------------
//you need to overide this with the function you want to thread
virtual void threadedFunction(){
if(verbose)printf("ofxThread: overide threadedFunction with your own\n");
}

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

#ifdef TARGET_WIN32
static unsigned int __stdcall thread(void * objPtr){
ofxThread* me = (ofxThread*)objPtr;
me->threadedFunction();
return 0;
}

#else
static void * thread(void * objPtr){
ofxThread* me = (ofxThread*)objPtr;
me->threadedFunction();
return 0;
}
#endif


#ifdef TARGET_WIN32
HANDLE myThread;
CRITICAL_SECTION critSec; //same as a mutex
#else
pthread_t myThread;
pthread_mutex_t myMutex;
#endif

bool threadRunning;
bool blocking;
bool verbose;
};


//-------------------------------------------------
ofxThread::ofxThread(){
threadRunning = false;
}

//-------------------------------------------------
ofxThread::~ofxThread(){
stopThread();
}

//-------------------------------------------------
bool ofxThread::isThreadRunning(){
//should be thread safe - no writing of vars here
return threadRunning;
}

//-------------------------------------------------
void ofxThread::startThread(bool _blocking, bool _verbose){

//have to put this here because the thread can be running
//before the call to create it returns
threadRunning = true;

#ifdef TARGET_WIN32
InitializeCriticalSection(&critSec);
myThread = (HANDLE)_beginthreadex(NULL, 0, this->thread, (void *)this, 0, NULL);
#else
pthread_mutex_init(&myMutex, NULL);
pthread_create(&myThread, NULL, thread, (void *)this);
#endif

blocking = _blocking;
verbose = _verbose;
}

//-------------------------------------------------
//returns false if it can't lock
bool ofxThread::lock(){
if(!threadRunning){
if(verbose)printf("ofxThread: need to call startThread first\n");
return false;
}

#ifdef TARGET_WIN32
if(blocking)EnterCriticalSection(&critSec);
else {
if(!TryEnterCriticalSection(&critSec)){
if(verbose)printf("ofxThread: mutext is busy \n");
return false;
}
}
if(verbose)printf("ofxThread: we are in -- mutext is now locked \n");
#else

if(blocking){
if(verbose)printf("ofxThread: waiting till mutext is unlocked\n");
pthread_mutex_lock(&myMutex);
if(verbose)printf("ofxThread: we are in -- mutext is now locked \n");
}else{
int value = pthread_mutex_trylock(&myMutex);
if(value == 0){
if(verbose)printf("ofxThread: we are in -- mutext is now locked \n");
}
else{
if(verbose)printf("ofxThread: mutext is busy - already locked\n");
return false;
}
}
#endif

return true;
}

//-------------------------------------------------
bool ofxThread::unlock(){

if(!threadRunning){
if(verbose)printf("ofxThread: need to call startThread first\n");
return false;
}

#ifdef TARGET_WIN32
LeaveCriticalSection(&critSec);
#else
pthread_mutex_unlock(&myMutex);
#endif

if(verbose)printf("ofxThread: we are out -- mutext is now unlocked \n");

return true;
}

//-------------------------------------------------
void ofxThread::stopThread(){
if(threadRunning){
#ifdef TARGET_WIN32
CloseHandle(myThread);
#else
pthread_mutex_destroy(&myMutex);
pthread_detach(myThread);
#endif
if(verbose)printf("ofxThread: thread stopped\n");
threadRunning = false;
}else{
if(verbose)printf("ofxThread: thread already stopped\n");
}
}

memoid
June 21st, 2008, 11:04 AM
Actually, I think I've actually identified the problem. I think it was the sleep() function in my thread loop. I understand why I need that if the loop is continuously running and doing heavy stuff, but do I need it in my case?

When I comment out the sleep line (As below), the behaviour looks a lot smoother and correct, maybe because as soon as I set the bHasRunThisFrame flag in the thread instance to false, the update function is called almost immediately (which is what I want), whereas with the sleep() function, maybe there was a delay of upto interval before the update kicked in?.... or something :P Is it bad to not have a sleep function in there?

// run the update function in another thread
void MSAThread::threadedFunction() {
while(isThreadRunning()) {
if( lock() ){
if(bAutoLoop || !bHasRunThisFrame) {
update();
bHasRunThisFrame = true;
unlock();
// ofSleepMillis(interval);
} else {
unlock();
}
}
}
}

TheCPUWizard
June 21st, 2008, 11:28 AM
The technuqie to solving ANY problem is to make things as simple as possible, but no simplier (Albert Einstein).

Create a test program.
Create a bunch of threads that all BLOCK (not sleep!) waiting for a signal.
Have the main program periodically call a method.
Have this method sen the signal to each thread.
Have the thread update a variable when it wakes, then send a signal to the main thread.
Have the main thread method wait until all signals have been recieved.

NO method should have more than about 5 lines of code.

When you get this working 100% stable, and fully understand what is happening, then (and only then) to you DERIVED from these solid working base classes to increase the functionallity from a simple variable update to your more complex processing (which should have already been 100% tested in a single threaded environment).

memoid
June 21st, 2008, 11:45 AM
Hi there, thanks for the reply.

I completely agree with what you are saying (in terms of simplifying the situation), but have a few areas which are unclear I'm afraid...

The steps you've outlined is exactly the behaviour I want... but I'm not sure how to do it. Almost every line you mentioned I have a question on!

"Create a bunch of threads that all BLOCK (not sleep!) waiting for a signal."
What exactly does this mean? Specifically how do I implement this? Is what I've done in the above post correct ? (waiting for an internal variable to be set in an infinite loop)

"Have the main program periodically call a method."
That would be my App::update();

"Have this method send the signal to each thread."
I guess this would be my Thread::runOnce(); but what kind of signal should that be? simply setting a property to true or are there other thread related methods?

"Have the thread update a variable when it wakes, then send a signal to the main thread."
what exactly do you mean by wakes?


"Have the main thread method wait until all signals have been received."
How do I do this? Is my Thread::waitForFinish() correct (and optimal)?

As you can see I don't know too much about multithreading :S

At the moment the behaviour I'm getting with my code above appears correct, but its something which I pretty much invented without experience, using lock() and unlock() (pthread_mutex_lock and pthread_mutex_unlock) to control the flow of the app and pause the main thread etc. I don't know if this is the best way to do it. Maybe the behaviour appears correct, but internally it is very inefficient? maybe there are better ways?

Thanks for breaking it down so nicely...

TheCPUWizard
June 21st, 2008, 11:52 AM
Hi there, thanks for the reply.

I completely agree with what you are saying (in terms of simplifying the situation), but have a few areas which are unclear I'm afraid...

The steps you've outlined is exactly the behaviour I want... but I'm not sure how to do it. Almost every line you mentioned I have a question on!

"Create a bunch of threads that all BLOCK (not sleep!) waiting for a signal."
What exactly does this mean? Specifically how do I implement this? Is what I've done in the above post correct ? (waiting for an internal variable to be set in an infinite loop)

No, thaat is about the worst you can do. Read the Posix threads tutorials at https://computing.llnl.gov/tutorials/pthreads/. read the WHOLE THING, but pay special attention to section 6 for this...

"Have the main program periodically call a method."
That would be my App::update();

Eventually, yes. For a simple test program...

int main()
{
CreateThreads();
while (!keypressed)
{
PRocessThreads(); // Here...
sleep(500);
}
}




"Have this method send the signal to each thread."
I guess this would be my Thread::runOnce(); but what kind of signal should that be? simply setting a property to true or are there other thread related methods?

The main method of the thread...

class MyThread
{
virtual void DoWork(); // very simple for now..
void Process()
{
WaitForWakeupMutex();
DoWork();
SetCompleteMutex();
}
}





"Have the thread update a variable when it wakes, then send a signal to the main thread."
what exactly do you mean by wakes?

See above, and go back and re-read the tutorials. ;) :wave:

"Have the main thread method wait until all signals have been received."
How do I do this? Is my Thread::waitForFinish() correct (and optimal)?

...once again...

As you can see I don't know too much about multithreading :S

At the moment the behaviour I'm getting with my code above appears correct, but its something which I pretty much invented without experience, using lock() and unlock() (pthread_mutex_lock and pthread_mutex_unlock) to control the flow of the app and pause the main thread etc. I don't know if this is the best way to do it. Maybe the behaviour appears correct, but internally it is very inefficient? maybe there are better ways?

As you can see by now, the mutexes are the way to do it....

Thanks for breaking it down so nicely...
No problem.... :wave: :wave: :wave:

memoid
June 21st, 2008, 12:15 PM
Hi, thanks for the detailed response. I had actually read that very page on posix threads programming... and its there I saw the condition variables etc. and was wondering maybe there's another way of doing this other than checking booleans in an infinite loop. Unfortunately it went a bit over my head - I'm a creative developer working on non-critical applications trying to avoid getting too involved in technical details if I can help it (hence using things like openframeworks or processing to get quicker results by hiding some of the inner complexity - at the cost of a slight performance loss perhaps).

So in short, from what I understand it is the condition variables which are destined to be my new best friend in the next few days? I will have another read of those pages...

memoid
June 21st, 2008, 08:12 PM
Hi Again,
After rereading the link you sent, I've put together what I understood of it and did a little test.

The output is perfectly in sync and if I have only 2 threads it seems very stable, but as I increase the number of threads it freezes after a few minutes, which ultimately means I've failed.

I would really appreciate it if you could point out where I'm going wrong,

Cheers,

Memo.



void App::setup() {
mainCounter = 0;
for(int i=0; i<NUM_THREADS; i++) thread[i].create();
}

void App::update(){
printf(" [ ");
mainCounter++;

for(int i=0; i<NUM_THREADS; i++) {
thread[i].wakeUp();
thread[i].waitForFinish();
}

printf(" %i ", mainCounter);

for(int i=0; i<NUM_THREADS; i++) printf(" %i ", thread[i].counter);

printf(" ] \n");
}



class MSAThread {

bool threadRunning;

pthread_t myThread;
pthread_mutex_t mutex;
pthread_cond_t cvWakeup;
pthread_cond_t cvComplete;

static void * thread(void * objPtr){
MSAThread* me = (MSAThread*)objPtr;
me->threadedFunction();
return 0;
}

public:
int counter;

~MSAThread() {
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cvWakeup);
pthread_cond_destroy(&cvComplete);
pthread_detach(myThread);
}

void create() {
counter = 0;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init (&cvWakeup, NULL);
pthread_cond_init (&cvComplete, NULL);

pthread_create(&myThread, NULL, thread, (void *)this);
threadRunning = true;
}

void threadedFunction(){
while(threadRunning) {
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cvWakeup, &mutex);

update();

pthread_cond_signal(&cvComplete);
pthread_mutex_unlock(&mutex);
}
}


void waitForFinish() {
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cvComplete, &mutex);
pthread_mutex_unlock(&mutex);
}


void wakeUp() {
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cvWakeup);
pthread_mutex_unlock(&mutex);
}


virtual void update() {
counter++;
int n = random() % 1000000;
float f = 0;
for(int i=0; i < n; i++) f = sin(i);

printf(" + ");
}

};

memoid
June 21st, 2008, 09:53 PM
Hi again, I'm going to call it a night for tonight. Where I am at is that I have no more hangs like above, the counters are in sync... but the threads are not running in parallel :( and I cannot figure out why... I can see in the log, the wakeup signals are sent straight away, but the 2nd thread does not go in till after thread 1 is finished .

desperately seeking help! :S

Cheers,

Memo.


Here is my code:


void App::setup() {
mainCounter = 0;
for(int i=0; i<NUM_THREADS; i++) thread[i].create(i);
}

void App::update(){
mainCounter++;

printf("\n[ **** %i : ", mainCounter);

for(int i=0; i<NUM_THREADS; i++) thread[i].wakeUp();


for(int i=0; i<NUM_THREADS; i++) thread[i].waitForFinish();

printf(" %i ", mainCounter);
for(int i=0; i<NUM_THREADS; i++) printf(" %i ", thread[i].counter);

printf(" **** ]");
}



class MSAThread {

bool threadRunning;

pthread_t myThread;
pthread_mutex_t mutex;
pthread_cond_t cvWakeup;
pthread_cond_t cvComplete;

static void * thread(void * objPtr){
MSAThread* me = (MSAThread*)objPtr;
me->threadedFunction();
return 0;
}

public:
int counter;
int index;

~MSAThread() {
threadRunning = false;
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cvWakeup);
pthread_cond_destroy(&cvComplete);
pthread_detach(myThread);
}

void create(int i) {
counter = 0;
index = i;
threadRunning = true;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init (&cvWakeup, NULL);
pthread_cond_init (&cvComplete, NULL);
pthread_create(&myThread, NULL, thread, (void *)this);
}

void threadedFunction(){
while(threadRunning) {
printf("{ %i waiting }", index);
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cvWakeup, &mutex);
printf("{ %i in }", index);

counter++;
update();

pthread_cond_signal(&cvComplete);
pthread_mutex_unlock(&mutex);
}
}


void wakeUp() {
printf("< %i sending wakeup >", index);
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cvWakeup);
printf("< %i wakeup sent>", index);
}

void waitForFinish() {
printf("< %i waiting finish >", index);
pthread_cond_wait(&cvComplete, &mutex);
pthread_mutex_unlock(&mutex);
printf("< %i finished >", index);
}


virtual void update() {
unsigned int n = -1;
float f = 0;
for(int i=0; i < n; i++) f = cos(sin(i));

printf(" { %i:%i } ", index, counter);
}

};


and my log

{ 0 waiting }{ 1 waiting }
[ **** 1 : < 0 sending wakeup >< 0 wakeup sent>< 1 sending wakeup >< 1 wakeup sent>< 0 waiting finish >{ 0 in } { 0:1 } { 0 waiting }< 0 finished >< 1 waiting finish >{ 1 in } { 1:1 } { 1 waiting }< 1 finished > 1 1 1 **** ]
[ **** 2 : < 0 sending wakeup >< 0 wakeup sent>< 1 sending wakeup >< 1 wakeup sent>< 0 waiting finish >{ 0 in } { 0:2 } { 0 waiting }< 0 finished >< 1 waiting finish >{ 1 in } { 1:2 } { 1 waiting }< 1 finished > 2 2 2 **** ]
[ **** 3 : < 0 sending wakeup >< 0 wakeup sent>< 1 sending wakeup >< 1 wakeup sent>< 0 waiting finish >{ 0 in } { 0:3 } { 0 waiting }< 0 finished >< 1 waiting finish >{ 1 in } { 1:3 } { 1 waiting }< 1 finished > 3 3 3 **** ]
[ **** 4 : < 0 sending wakeup >< 0 wakeup sent>< 1 sending wakeup >< 1 wakeup sent>< 0 waiting finish >{ 0 in } { 0:4 } { 0 waiting }< 0 finished >< 1 waiting finish >{ 1 in } { 1:4 } { 1 waiting }< 1 finished > 4 4 4 **** ]
[ **** 5 : < 0 sending wakeup >< 0 wakeup sent>< 1 sending wakeup >< 1 wakeup sent>< 0 waiting finish >{ 0 in } { 0:5 } { 0 waiting }< 0 finished >< 1 waiting finish >{ 1 in } { 1:5 } { 1 waiting }< 1 finished > 5 5 5 **** ]
[ **** 6 : < 0 sending wakeup >< 0 wakeup sent>< 1 sending wakeup >< 1 wakeup sent>< 0 waiting finish >{ 0 in } { 0:6 } { 0 waiting }< 0 finished >< 1 waiting finish >{ 1 in } { 1:6 } { 1 waiting }< 1 finished > 6 6 6 **** ]
[ **** 7 : < 0 sending wakeup >< 0 wakeup sent>< 1 sending wakeup >< 1 wakeup sent>< 0 waiting finish >{ 0 in } { 0:7 } { 0 waiting }< 0 finished >< 1 waiting finish >{ 1 in } { 1:7 } { 1 waiting }< 1 finished > 7 7 7 **** ]
[ **** 8 : < 0 sending wakeup >< 0 wakeup sent>< 1 sending wakeup >< 1 wakeup sent>< 0 waiting finish >{ 0 in } { 0:8 } { 0 waiting }< 0 finished >< 1 waiting finish >{ 1 in } { 1:8 } { 1 waiting }< 1 finished > 8 8 8 **** ]
[ **** 9 : < 0 sending wakeup >< 0 wakeup sent>< 1 sending wakeup >< 1 wakeup sent>< 0 waiting finish >{ 0 in } { 0:9 } { 0 waiting }< 0 finished >< 1 waiting finish >{ 1 in } { 1:9 } { 1 waiting }< 1 finished > 9 9 9 **** ]
[ **** 10 : < 0 sending wakeup >< 0 wakeup sent>< 1 sending wakeup >< 1 wakeup sent>< 0 waiting finish >{ 0 in } { 0:10 } { 0 waiting }< 0 finished >< 1 waiting finish >{ 1 in } { 1:10 } { 1 waiting }< 1 finished > 10 10 10 **** ]
[ **** 11 : < 0 sending wakeup >< 0 wakeup sent>< 1 sending wakeup >< 1 wakeup sent>< 0 waiting finish >{ 0 in } { 0:11 } { 0 waiting }< 0 finished >< 1 waiting finish >{ 1 in } { 1:11 } { 1 waiting }< 1 finished > 11 11 11 **** ]

TheCPUWizard
June 21st, 2008, 10:29 PM
... I can see in the log, the wakeup signals are sent straight away, but the 2nd thread does not go in till after thread 1 is finished .

Relaize that (one a single core machine) only one thread EVER executes at any time. A thread will consume the CPU until its time slice expires or it gets blocked.

memoid
June 21st, 2008, 10:36 PM
Hi there, I should have mentioned... I'm running on an 8-core Mac Pro. When I remove all the mutex stuff I can see they are all running simultaneously. In the update function I put a for-loop upto (unsigned)(-1) so it would be extra slow and it would be easy to track. Without the mutex's I get dumps on screen in bunches... but all unsynchronized. THis latest code I posted seems to me that it should run in parallel, but it is not!

TheCPUWizard
June 21st, 2008, 10:49 PM
I will take another look...unfortunately I am not in a position to compile it and run it.

Your next to last version had a bug in the for loop in the main thread, but I see that is resolved in your latest. ....

memoid
June 21st, 2008, 10:55 PM
Hi, much appreciated. Yes I realized in that version (the 2nd from last), putting the wait() in the same loop as the wakeup() would cause the main thread to pause in the first iteration of the loop without getting a chance to wake the 2nd one up.

I changed that for the 2nd version, all the wakeups are sent, and then the main thread is set to wait for all the signals. I just don't understand why the threads are still waiting when the signal is sent!

Thanks again for your help,

TheCPUWizard
June 21st, 2008, 11:49 PM
I think we are both brain dead...look at the update. it will ONLY print the value ONCE per cycle....

Change it to:

virtual void update()
{
for(int i=0; i < 20; i++)
{
printf(" { %i:%i } ", index, counter);
sleep(0); // simply allows other threads to run.
}
}

memoid
June 22nd, 2008, 08:32 AM
Hi, I"m not sure I understand. That update is per thread, and the for loop was to simulate the thread doing something heavy for quite long. I do want only one printf per update per thread, and if 4 threads are running in parallel, I should get all 4 printfs at roughly the same time (or at least not sequentially).

I've given up on the condition variables I'm afraid and gone back to the boolean route. It works quite stable (left it running overnight logging the frame counts, and not a single frame deviation in any thread).



class MSAThread : public ofxThread {

int counter;
int index;
bool bOkToRun;

public:

~MSAThread() {
stopThread();
}

void create(int i = 0) {
counter = 0;
index = i;
bOkToRun = false;
startThread(true, false); // blocking, verbose
}

void threadedFunction(){
while(threadRunning) {
if(bOkToRun) {
lock();
counter++;
update();
bOkToRun = false;
unlock();
}
ofSleepMillis(1);
}
}


void wakeUp() {
lock();
bOkToRun = true;
unlock();
}

void waitForFinish() {
lock();
unlock();
}

int getCounter() { return counter; }

void logCounter() { printf("%i ", counter); }

virtual void update() {
unsigned int n = (unsigned)-1;
float f = 0;
for(int i=0; i < n; i++) f = cos(sin(i));
printf(" { %i:%i } ", index, counter);
}
};

TheCPUWizard
June 22nd, 2008, 08:37 AM
Hi, I"m not sure I understand. That update is per thread, and the for loop was to simulate the thread doing something heavy for quite long. I do want only one printf per update per thread, and if 4 threads are running in parallel, I should get all 4 printfs at roughly the same time (or at least not sequentially).

NO if you only do one print from each thread, then you will see the output s consequtibvely. Make it so that there are muiltiple outputs with a sleep or yielf and you will se the correct results.


I've given up on the condition variables I'm afraid and gone back to the boolean route. It works quite stable (left it running overnight logging the frame counts, and not a single frame deviation in any thread).

BIG mistake. It may be stable now, but what load is it putting on the system??? And ANY change to your environment may introduce destabilization.

But hey it is your code....good bye.

memoid
June 22nd, 2008, 08:58 AM
NO if you only do one print from each thread, then you will see the output s consequtibvely. Make it so that there are muiltiple outputs with a sleep or yielf and you will se the correct results.

I see what you mean, I've modified the thread update function to printf during the for and it is true that all the threads are working, but unfortunately the frame counts are differing and growing out of sync quite rapidly. THis is only an issue when the thread updates vary in length (i.e. when I do a constant long for loop they stay in sync, but when I do the for upto a random number, they grow out of sync rapidly).

BIG mistake. It may be stable now, but what load is it putting on the system??? And ANY change to your environment may introduce destabilization.

I'd much rather do it the proper way with the condition variables, but I just can't get it to work! I've included my code below. Do I need both the sleep commands in the thread update and main update? And why are the framecounts growing out of sync?


void threadedFunction(){
while(threadRunning) {
lock();
pthread_cond_wait(&cvWakeup, &myMutex);
counter++;
update();
unlock();
ofSleepMillis(1);
}
}


void wakeUp() {
lock();
pthread_cond_signal(&cvWakeup);
unlock();
}

void waitForFinish() {
lock();
unlock();
}

virtual void update() {
unsigned int n = random();
float f = 0;
for(int i=0; i < n; i++) {
if(i%10000000 == 0) printf(" { %i WORKING } ", index);
f = cos(sin(i));
}
printf(" { %i:%i } ", index, counter);
}



void App::update(){

printf("\n[ **** %i : ", ofGetFrameNum());
for(int i=0; i<NUM_THREADS; i++) thread[i].wakeUp();

ofSleepMillis(1);

for(int i=0; i<NUM_THREADS; i++) thread[i].waitForFinish();

printf(" %i ", ofGetFrameNum());
for(int i=0; i<NUM_THREADS; i++) printf(" %i ", thread[i].getCounter());

printf(" **** ]");
}


**EDIT ** the lock() and unlock() simply do pthread_mutex_lock and unlock