2
votes

I have a question regarding use of pthread condition variables. As a general use case is like this

//thread 1:
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
do_something()
pthread_mutex_unlock(&mutex);

//thread 2:
pthread_cond_signal(&cond);  

Now I know that pthead_cond_wait will unlock mutex and go to sleep and when awaken it will lock the mutex and then return from call but how to ensure that signal from thread 2 reaches thread 1 after thread 1 is in condition wait. It could occur that thread2 runs first and then thread1 causing lost wake up.

If I use mutex lock in thread 2 again then also it may happen that thread2 will get lock it will signal and thread1 is still trying to acquire lock. This will again result in lost wake up.

How to ensure that signal from condition variable reaches thread waiting on that ?

Thanks

2
You ensure it by not using condition variables as predicates. They're used to signal a change in some predicate; not be the predicate themselves. Though vaguely related, read this, as it has some trivial, but important, aspects of how to use cvars, mutexes, and predicate changes.WhozCraig

2 Answers

4
votes

You "general use case" is not correct. A condition variable must be paired with a condition over some shared state, known as a predicate. The general use case is:

Thread 1:

pthread_mutex_lock(&mutex);
while (!condition)
    pthread_cond_wait(&cond, &mutex);
do_something(); /* Requiring 'condition' to be true */
pthread_mutex_unlock(&mutex);

Thread 2:

pthread_mutex_lock(&mutex);
do_something_else(); /* That sets 'condition' true */
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);

...where condition is over some shared state protected by mutex - for example, condition might be checking that a shared queue is non-empty.

There can be no lost wakeup in this structure, because the waiting thread always checks the condition before waiting. If the condition is already true, it doesn't wait - and because it holds the mutex protecting the condition, it can't become true between the check and the wait either.

(Note that pthread_cond_broadcast() is the generally correct function to use, and pthread_cond_signal() is an optimisation that is applicable in many cases).

0
votes

It is completely based on your design. You can use a bool variable(say isSignalled) to synchronize both. Something like below(please take it as an idea)

//thread 1:
pthread_mutex_lock(&mutex);
if(isSignalled == 0){
    pthread_cond_wait(&cond, &mutex);
}
isSignalled = 0;
do_something()
pthread_mutex_unlock(&mutex);

//thread 2:
pthread_mutex_lock(&mutex);
isSignalled = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);