Reputation: 19331
I have a simple application that interfaces with different pieces of hardware. For each piece of hardware, I spawn a pthread_t
against a unique monitor function, for a total of 6 threads: 1 manager thread, and 5 worker threads.
Each thread has a common initialization routine where it waits for the manager thread to wake it up via:
pthread_mutex_lock(&mMutex);
pthread_cond_wait(&mMutex, &condVar);
pthread_mutex_lock(&mMutex);
The main thread then wakes up all of the threads by signalling them one at a time:
pthread_cond_wait(&mMutex1, &condVar1);
pthread_cond_wait(&mMutex2, &condVar2);
...
pthread_cond_wait(&mMutex5, &condVar5);
The code actually works fine, but this is because I am lucky with the timing. There is the remote but existent chance that when the main/manager thread issues pthread_cond_signal
, that the thread is not yet done initialization. I need to find a way to guarantee that each and every condition variable has had a wait
call made on it by its respective worker thread.
I could always create a status boolean that is set within the corresponding mutex, but I cannot atomically do both the set
and the wait
operation in one instruction, so far as I know. I could also make use of a pthread_barrier_t
, but that just guarantees all the threads are one or two instructions before making their respective wait
calls.
Is there a tried-and-true method of being certain that the wait
call has been made, or do I need to employ some means of timed wait looping/checking?
Thank you.
Upvotes: 1
Views: 130
Reputation: 239341
A condition variable should always be paired with a mutex-protected predicate. In this case, your predicate can just be a simple flag: in the worker thread, it would look like:
pthread_mutex_lock(&mMutex);
while (!woken)
pthread_cond_wait(&mMutex, &condVar);
pthread_mutex_unlock(&mMutex);
In the manager thread, it would look like:
pthread_mutex_lock(&mMutex);
woken = 1;
pthread_cond_signal(&condVar);
pthread_mutex_unlock(&mMutex);
Here, if the manager thread acquires the mutex first, then by the time the worker acquires the mutex the flag will be set, and it won't wait at all; if the worker acquires the mutex first, then manager won't be able to acquire the mutex and set the flag until the worker has been held at the pthread_cond_wait
.
Upvotes: 1
Reputation: 400682
I could always create a status boolean that is set within the corresponding mutex, but I cannot atomically do both the set and the wait operation in one instruction, so far as I know.
That's the right way to do it -- you can do a set and wait operation atomically, because of the way condition variables interact with mutexes. When you do a pthread_cond_wait()
operation, you must have the mutex that you pass in be locked. If you correspondingly have that same mutex locked when you do a pthread_cond_signal()
, the waiting thread doesn't wake up until the signalling thread unlocks the mutex.
So, the following code would do what you want:
// Flag indicating if the worker thread is waiting or not
bool waiting = false;
...
// Worker thread code
... do stuff ...
while (!condition_is_not_satisfied())
{
pthread_mutex_lock(&mutex);
waiting = true;
pthread_cond_wait(&cond, &mutex);
waiting = false;
pthread_mutex_unlock(&mutex);
}
...
// Signalling thread code
pthread_mutex_lock(&mutex);
if (waiting)
{
// Worker thread is waiting -- signal it to wake up
pthread_cond_signal(&cond);
}
else
{
// Worker thread has not yet entered the wait state -- do something else
}
pthread_mutex_unlock(&mutex);
Upvotes: 3