我有我与使用条件变量的代码死锁的问题。 这比纯粹的代码问题,设计问题。 我没有问题,实际编写代码,一旦我理解正确的设计。 我有以下情形:
- 线程条件变量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只做了notify_all()之前线程A获取该互斥锁或同时线程A是在条件变量等待。
另外一个关键的位置,虽然是while循环等待the_condition成为事实。 一旦A拥有互斥它不应该是可能的,直到已经测试the_condition任何其他线程改变the_condition,发现假的,并开始等待(从而释放互斥体)。
问题的关键是:你真正等待的是为the_condition的价值变得不为零,标准:: condition_variable :: notify_all只是告诉你,线程B认为线程A应该唤醒和复试。
条件变量必须始终与互斥,以避免由一个线程准备等待和之前所述第一线程上它导致死锁实际上等待其可以用信号通知条件另一个线程创建的竞争条件相关联。 该线程会永远等待一个永远不会发送的信号。 任何互斥可以使用,有互斥和条件变量之间没有显式的联系。