Reputation: 15091
I'm trying to learn the difference between mutexes and conditional variables and am confused by the following code.
// Lock mutex and then wait for signal to relase mutex
pthread_mutex_lock( &count_mutex );
/*Wait while functionCount2() operates on count
mutex unlocked if condition varialbe in functionCount2() signaled. <-- so then why call pthread_mutex_unlock() 3 lines latter if it's already unlocked?*/
pthread_cond_wait( &condition_var, &count_mutex );
count++;
printf("Counter value functionCount1: %d\n",count);
pthread_mutex_unlock( &count_mutex );
According to the docs pthread_cond_wait()
"atomically release mutex and cause the calling thread to block on the condition variable" so what's the point of pthread_mutex_lock( &count_mutex );
if pthread_cond_wait()
just unlocks it and what's the point to the latter call pthread_mutex_unlock() since pthread_cond_wait()
had already unlocked it?
To me it would make sense if pthread_cond_wait() did not take a mutex, and I thought that was its point.
Upvotes: 2
Views: 2730
Reputation: 1001
Lets have a look at the following two functions, waiting and notifying. Both run in two separate threads and use globally defined variables value, mutex and cond. Let's assume that the waiting thread starts first and locks the mutex. Now the condition "value is zero" can be tested safely, because the lock guarantees no other thread can change the value. In the next step, our waiting thread is waiting on the conditional variable for a signal from the notifying function that the value has been changed and it should be checked again.
void* waiting(void* arg)
{
pthread_mutex_lock(&mutex);
while(value == 0)
{
pthread_cond_wait(&cond, &mutex);
}
printf("waiter %d releases\n", *tid);
pthread_mutex_unlock(&mutex);
}
Now lets see what is going with the notifying function. Do you remember that we have locked the mutex in the waiting thread? Without releasing it, our notifying function never can obtain the mutex and change the value. That is the reason why the pthread_cond_wait releases it. No, the function does not release it finally, only for the period when the function is blocked. Now our notifying thread can change the value and send a signal to the pthread_cond_wait, that something has happened. When the pthread_cond_wait unblocks (returns), the mutex is locked again!
void* notifying(void* arg)
{
pthread_mutex_lock(&mutex);
value = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
It is interesting, that it is common to wait on a condition variable in a loop, checking the condition again and again. Why? Sometimes pthread_cond_wait unblocks without getting signals from the notifying function (so called spurious signals).
Upvotes: 0
Reputation: 340426
First let's define some terms that might be a bit confusing:
condition: this is the expression that a thread uses to determine whether or not something has happened or that work needs to be done. For example a condition might be that a queue is not empty.
condition variable: this is a synchronization object that the pthread library (or something similar) makes available to let a thread wait for a condition to change. A thread can 'wait' on a condition variable, then when another thread signals that condition variable, the waiting thread will wake up.
Note that a "condition" is a different thing than a "condition variable".
When using condition variables, a thread needs to check the condition (whatever that is), then if the condition isn't met, it can wait on the condition variable until something signals that it should check the condition again.
However, this sequence of events:
isn't atomic by itself - if between step 1 and 2 another thread signals the condition variable, then the waiting thread may never wake up (condition variables don't remember that a signal has occurred in the past; when signaled they will only unblock a thread that is already waiting). To avoid this problem, condition variables must be used with a pattern that ensures that the two steps will happen atomically with respect to other threads dealing with the condition and condition variable. That pattern is:
pthread_cond_wait()
call. This ensures that the race condition between steps 1 and 2 above cannot occur, because anything that updates the condition will not be able to acquire the mutex until the pthread_cond_wait()
call has prepared the thread to wait. At that point the pthread_cond_wait()
function will release the mutex, which will allow the updating thread to acquire the mutex and update the condition.Upvotes: 4