Re: multithreading on OSX
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
Code:
void MSAThread::threadedFunction() {
while(isThreadRunning()) {
if( lock() ){
if(bAutoLoop || !bHasRunThisFrame) {
update();
bHasRunThisFrame = true;
unlock();
// ofSleepMillis(interval);
} else {
unlock();
}
}
}
}
Re: multithreading on OSX
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).
Re: multithreading on OSX
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...
Re: multithreading on OSX
Quote:
Originally Posted by memoid
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...
Quote:
"Have the main program periodically call a method."
That would be my App::update();
Eventually, yes. For a simple test program...
Code:
int main()
{
CreateThreads();
while (!keypressed)
{
PRocessThreads(); // Here...
sleep(500);
}
}
Quote:
"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...
Code:
class MyThread
{
virtual void DoWork(); // very simple for now..
void Process()
{
WaitForWakeupMutex();
DoWork();
SetCompleteMutex();
}
}
Quote:
"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:
Quote:
"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...
Quote:
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....
Quote:
Thanks for breaking it down so nicely...
No problem.... :wave: :wave: :wave:
Re: multithreading on OSX
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...
Re: multithreading on OSX
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.
Code:
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");
}
Code:
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(" + ");
}
};
Re: multithreading on OSX
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:
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(" **** ]");
}
Code:
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
Code:
{ 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 **** ]
Re: multithreading on OSX
Quote:
Originally Posted by memoid
... 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.
Re: multithreading on OSX
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!
Re: multithreading on OSX
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. ....
Re: multithreading on OSX
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,
Re: multithreading on OSX
I think we are both brain dead...look at the update. it will ONLY print the value ONCE per cycle....
Change it to:
Code:
virtual void update()
{
for(int i=0; i < 20; i++)
{
printf(" { %i:%i } ", index, counter);
sleep(0); // simply allows other threads to run.
}
}
Re: multithreading on OSX
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).
Code:
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);
}
};
Re: multithreading on OSX
Quote:
Originally Posted by memoid
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.
Quote:
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.