2
votes

I am going through condition variable article at following location

http://software.intel.com/en-us/blogs/2010/10/01/condition-variable-support-in-intel-threading-building-blocks/

Here we have following code as example

#include "tbb/compat/condition_variable"  
using namespace std;
condition_variable my_condition;
tbb::mutex my_mtx;
bool present = false;

void producer() {
        unique_lock<tbb::mutex> ul( my_mtx );
        present = true;
        my_condition.notify_one();
}

void consumer() {
        while( !present ) {
            unique_lock<tbb::mutex> ul( my_mtx );
            my_condition.wait( ul );
        }
}

My understanding is that we use condition variable to wait on an event. I have following questions

  1. Why are we using mutex here while we are using condition variable?
  2. In consumer() function in while loop we are taking mutex and waiting on condition, how can producer function can lock mutex if consumer already taken it and how can it notify it doesn't it a deadlock?
  3. How unique_lock is different from scoped_lock?

Thanks for your help in clarfiying my questions.

4

4 Answers

3
votes

Why are we using mutex here while we are using condition variable?

The basics of the condition variable require a lock to work correctly.
Only the thread with the lock should be trying to change the state of the condition variable (ie by calling one of the condition variable functions (it is also to protect the object you are really working on)).

In consumer() function in while loop we are taking mutex and waiting on condition, how can producer function can lock mutex if consumer already taken it

When you call wait() on the condition variable the thread is put to sleep and the mutex is released. When a thread is woken up it must re-acquire the lock before the function wait() returns to the user code.

and how can it notify it doesn't it a deadlock?

It does not deadlock because wait() is releasing the lock before putting the thread to sleep.

How unique_lock is different from scoped_lock?

In this context none. But if you have any specific implementation of these then please specify the implementation and we can discuss it in more detail.

1
votes

It should be (for clarity):

void producer() {
        unique_lock<tbb::mutex> ul( my_mtx ); // protect present
        present = true;
        my_condition.notify_one();
}

void consumer() {
        unique_lock<tbb::mutex> ul( my_mtx );   // protect preset
        while( !present ) {
            my_condition.wait( ul );
        }
}

From: http://www.boost.org/doc/libs/1_46_0/doc/html/thread/synchronization.html#thread.synchronization.condvar_ref.condition_variable.wait which is very similar.

void wait(boost::unique_lock& lock)

Precondition: lock is locked by the current thread, and either no other thread is currently waiting on *this, or the execution of the mutex() member function on the lock objects supplied in the calls to wait or timed_wait in all the threads currently waiting on *this would return the same value as lock->mutex() for this call to wait.

Effects: Atomically call lock.unlock() and blocks the current thread. The thread will unblock when notified by a call to this->notify_one() or this->notify_all(), or spuriously. When the thread is unblocked (for whatever reason), the lock is reacquired by invoking lock.lock() before the call to wait returns. The lock is also reacquired by invoking lock.lock() if the function exits with an exception.

Postcondition: lock is locked by the current thread.

0
votes

Mutex is for mutual exclusion (so that the producer & consumer don't alter global state without locking), condition variable is to impose some ordering.

0
votes
  1. The mutex is used to protect the condition variable
  2. the mutex is unlocked automatically when you invoke my_condition.wait(), and when my_conditioin.wait() return, it unlock the mutex, then you can test the condition in while(!present). That's, if wait() can't lock the mutex because another thread is faster, it will be blocked. Once the faster thread finished, this wait() returned with mutex locked, but the condition maybe become false, then the thread wait again. So, the mutex is use to protect the condition varaible, as the 1st answer said.