Quote:
Originally Posted by brfindla
when I try to trigger the condition on n number of threads shortly after thread creation
|
If I can guess correctly from your code, variable
tnum is a thread number, and you do one triggering for each subsidiary thread that you want to wake up. This is a good thing. (It would be a confusing thing if you were to want to do one trigger and expect all the subsidiary threads to wake up.)
Quote:
Originally Posted by brfindla
there appears to be a race condition.
|
This is a quite common indication that pthreads are not being used properly.
Quote:
Originally Posted by brfindla
(1) if the condition (&signal_request[tnum]) occurs prior to blocking on the pthread_cond_wait() is it true that it will not be recognized?
|
No, not if you use pthreads correctly.
Quote:
Originally Posted by brfindla
(2) How can I know that it is "safe" to send the condition so that it will be recognized?
|
It will be safe from the very beginning, even before you initialize the subsidiary threads, provided you use pthreads properly.
Before I go into details on your questions, may I make a suggestion? Use an array of mutexes, so there's a one-to-one correspondence between mutexes and condition variables. That's the ordinary way of doing what you seem to be doing. You could bundle it all up in one mutex if you want, but that tends to be a bad habit, because it can reduce the amount of parallelism among threads.
Here's an important point. To use condition variables for coordination among threads, you need three things:
- a mutex;
- a corresponding condition variable; and
- a corresponding condition that you can actually test.
For example, suppose that a subsidiary thread is supposed to do something if global variable
alpha is greater than or equal to global variable
beta.
Your primary thread grabs the mutex protecting
alpha and
beta, changes one or both of those variables, and releases the mutex. It then calls
pthread_cond_signal() to wake up the subsidiary thread.
Your subsidiary thread figures out when to run by doing the following things, but in a particular sequence which I'll describe in a moment:
- testing the condition itself;
- using the mutex; and
- using the condition variable.
Here's what your subsidiary thread should do:
- Lock the mutex.
- Test the condition. If the test passes, then go to step 5. Note that this covers the case of the condition being true even before your subsidiary thread starts!
- Since the test does not pass, do a pthread_cond_wait(). Do not unlock the mutex before you do this; the pthread_cond_wait() will do this atomically with the waiting. If you unlocked the mutex first, it could be that some other thread makes the condition true, and then you do the pthread_cond_wait() to wait for a condition that's already true. Deadlock! So let the pthread_cond_wait() unlock the mutex for you.
- When the subsidiary thread wakes up from the pthread_cond_wait(), the mutex will have been locked for you again. (Again, atomicity is important). But there's no guarantee that the condition will have actually changed. Go back to step 2 (which relies on the mutex being locked) and test the condition again.
- Do what you need to do with the condition being true. Presumably you will, in the process, make the condition false. If you didn't do that, your thread would then most likely wake up again and do everything a second time!
- Unlock the mutex. Go back to step 1 to wait for the condition to be true again.
In your case, where the condition to be tested would be very simple, I would recommend an array of elements of type
short, initialized to zero. When you want to wake up a subsidiary thread, set its element in this array to nonzero. Make the subsidiary thread check this element for nonzero. When the subsidiary thread is finished processing, it should set the element to zero again.
A by-product of this arrangement is that your primary thread can lock the mutex for a given thread and test that element in this array to see whether the thread is currently running. (And then, I hope, unlock the corresponding mutex again!)
This whole thing probably seems like a magical incantation to you, something you do because I've advised you to do it. If you don't have a thorough understanding of why you need to do these things in the specified order, please do one of two things.
- If you are taking a course that uses POSIX threads because the course is required, and you'll never use pthreads again, talk to your professor or teaching assistant or an uebergeek fellow student to clarify why you'd want to do things as specified above.
- If, on the other hand, you're going to use POSIX threads in an ongoing project, or later in your career, or you are simply curious about how it works so at least you don't write the kind of synchronization bug that might show up once in a million years (Murphy's law, indeed), then run, don't walk, to your nearest bookseller and order the fine book Programming with POSIX Threads, authored by David R. Butenhof and published by Addison Wesley. Then instead of going on that date with your main squeeze this Saturday, invite her over to your place with a good novel while you read this book pretty much from cover to cover.
(My experience with the corresponding O'Reilly book is that it's arguably complete, but so inadequate that it's downright dangerous.)
Hope this helps.