Question

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.

Was it helpful?

Solution

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);

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top