Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Condition variable deadlock

I have a problem with a deadlock in my code related to the use of condition variables. This is more of a design question than a pure code question. I have no problem actually writing code once I understand the correct design. I have the following scenario:

  1. Thread A waits on a condition variable.
  2. Thread B calls notify_all, and thread A wakes up.

This is of course what I want to happen, and is what does happen when everything works as expected. But sometimes, I get the following scenario instead:

  1. Thread A executes the code right before it begins to wait on the condition variable.
  2. Thread B calls notify_all, thinking that thread A is waiting.
  3. Thread A begins waiting on the condition variable, not realizing that thread B already told it to stop waiting. Deadlock.

What is the best way to resolve this? I can't think of a reliable way to check whether thread A is actually waiting, in order to know when I should call notify_all in thread B. Do I have to resort to timed_lock? I would hate to.

like image 266
Philip Bennefall Avatar asked Apr 09 '13 20:04

Philip Bennefall


People also ask

Does condition variable release lock?

Condition variables are synchronization primitives that enable threads to wait until a particular condition occurs. Condition variables are user-mode objects that cannot be shared across processes. Condition variables enable threads to atomically release a lock and enter the sleeping state.

Why does condition variable need a lock?

If you didn't have a lock associated with the cv then your thread waiting on the cv might wake up then try to (and fail) to acquire the lock associated with the data and therefore have to yield again.

What is condition variable C++?

Condition variable. A condition variable is an object able to block the calling thread until notified to resume. It uses a unique_lock (over a mutex ) to lock the thread when one of its wait functions is called.

What is mutex and condition variable?

While mutex implement synchronization by controlling thread access to data, condition variables allow threads to synchronize based upon the actual value of data. Without condition variables, the programmer would need to have threads continually polling (possibly in a critical section), to check if the condition is met.


2 Answers

During the period just before Thread A waits on condition variable it must be holding a mutex. The easiest solution is to make sure that Thread B is holding the same mutex at the time it calls notify_all. So something like this:

std::mutex m;
std::condition_variable cv;
int the_condition = 0;

Thread A: {
  std::unique_lock<std::mutex> lock(m);
  do something
  while (the_condition == 0) {
    cv.wait(lock);
  }
  now the_condition != 0 and thread A has the mutex
  do something else
} // releases the mutex;

Thread B: {
  std::unique_lock<std::mutex> lock(m);
  do something that makes the_condition != 0
  cv.notify_all();
} // releases the mutex

This guarantees that Thread B only does the notify_all() either before Thread A acquires the mutex or while Thread A is waiting on the condition variable.

The other key here, though, is the while loop waiting for the_condition to become true. Once A has the mutex it should not be possible for any other thread to change the_condition until A has tested the_condition, found it false, and started waiting (thus releasing the mutex).

The point is: what you are really waiting for is for the value of the_condition to become non-zero, the std::condition_variable::notify_all is just telling you that thread B thinks thread A should wake up and retest.

like image 178
Wandering Logic Avatar answered Sep 20 '22 11:09

Wandering Logic


A condition variable must always be associated with a mutex to avoid a race condition created by one thread preparing to wait and another thread which may signal the condition before the first thread actually waits on it resulting in a deadlock. The thread will be perpetually waiting for a signal that is never sent. Any mutex can be used, there is no explicit link between the mutex and the condition variable.

like image 31
oiyio Avatar answered Sep 16 '22 11:09

oiyio