C++11 我能确保 condition_variable.wait() 不会错过通知吗?

7

我有一个线程1执行以下代码:

unique_lock<mutex> ul(m);
while(condition == true)
    cv.wait(ul);

同时执行这段代码的第二个线程:

condition = false;
cv.notify_one();

很不幸,我遇到了一个时间问题:

T1: condition checks true
                            T2: condition set to false
                            T2: cv.notify_one()
T1: cv.wait()

线程1完全错过了通知,仍然阻塞在wait()上。我尝试使用带有谓词的wait()版本,但基本上结果相同。也就是说,谓词的主体执行检查,但在返回之前,条件的值被更改并发送了通知。然后谓词返回。

我该如何解决这个问题?


1
在编程中,有必要同时具有要检查的布尔值和条件变量吗?难道你不能只等待条件变量吗? - Vaughn Cato
这段代码被大大简化了。(忘记提到了,抱歉。)检查和设置条件不仅涉及加载/翻转布尔值,事实上,我认为这个错误更容易被注意到,因为处理条件需要花费相当可观的时间。 - screwnut
1
@VaughnCato 不行。cv 只能被用于 实际变量 - curiousguy
3个回答

8

您应该通过在更改标志之前,让线程2锁定条件的互斥量来解决这个竞态条件。

您描述了未保护的标记和条件发生的典型竞态条件。这些竞态条件是条件使用中互斥锁模式的原因。简单地说,始终使用互斥锁来保护涉及检查条件值的变量。

对于线程2的代码:

unique_lock<mutex> ul(m);
condition = false;
cv.notify_one();

啊,我就知道它会很简单。谢谢你。然后...我现在要回去看我的计算机科学书了... :) - screwnut

0

由于对condition的读写访问冲突,您遇到了一个数据竞争。这意味着程序的行为未定义

cv上的竞争条件是您最不用担心的事情:程序可能会做任何事情!


0
你应该使用std::wait的预测形式来检查一个全局变量。这样可以同时解决可能出现的竞争条件。如果线程1先到达wait(),那么它会被通知解除阻塞,就像你预期的那样。如果线程2先到达notify_all(),那么线程1会被stopCondition全局布尔变量解除阻塞。
全局
mutex m;
atomic_bool stopCondition{false};

线程1

unique_lock<mutex> ul(m);
cv.wait(ul, [&stopCondition](){return stopCondition;})

线程2
{
  unique_lock<mutex> ul(m);
  stopCondition = true;
  cv.notify_one();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接