Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
287 views
in Technique[技术] by (71.8m points)

c++ - 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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...