条件变量死锁 [英] Condition variable deadlock
问题描述
我的代码中存在与使用条件变量有关的死锁问题.这更多的是设计问题,而不是纯粹的代码问题.了解正确的设计后,我便可以真正编写代码了.我有以下情况:
- 线程A等待条件变量.
- 线程B调用notify_all,线程A醒来.
这当然是我想发生的事情,并且当一切都按预期工作时会发生什么.但是有时候,我得到的是以下情况:
- 线程A在开始等待条件变量之前立即执行代码.
- 线程B调用notify_all,认为线程A正在等待.
- 线程A开始等待条件变量,但没有意识到线程B已经告诉它停止等待.死锁.
解决此问题的最佳方法是什么?我想不出一种可靠的方法来检查线程A是否实际上正在等待,以便知道何时应在线程B中调用notify_all.我是否必须求助于timed_lock?我讨厌.
在线程A等待条件变量之前的一段时间内,它必须持有互斥量.最简单的解决方案是确保线程B在调用notify_all时保持相同的互斥量.像这样:
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
这保证了线程B仅在线程A获取互斥量之前或在线程A等待条件变量时才执行notify_all().
不过,这里的另一个关键是while循环,等待the_condition变为true.一旦A具有互斥量,在A测试了_condition,发现其为false并开始等待(从而释放互斥量)之前,其他任何线程都不可能更改_condition.
重点是:您真正在等待的是the_condition的值变为非零,std :: condition_variable :: notify_all只是告诉您线程B认为线程A应该唤醒并重新测试. /p>
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:
- Thread A waits on a condition variable.
- 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:
- Thread A executes the code right before it begins to wait on the condition variable.
- Thread B calls notify_all, thinking that thread A is waiting.
- 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.
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.
这篇关于条件变量死锁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!