我理解如何使用条件变量(此构造的名称为IMO,因为cv对象既不是变量也不表示条件)。所以我有一对线程,canonically使用Boost.Thread设置为:
bool awake = false;
boost::mutex sync;
boost::condition_variable cv;
void thread1()
{
boost::unique_lock<boost::mutex> lock1(sync);
while (!awake)
cv.wait(lock1);
lock1.unlock(); // this line actually not canonical, but why not?
// proceed...
}
void thread2()
{
//...
boost::unique_lock<boost::mutex> lock2;
awake = true;
lock2.unlock();
cv.notify_all();
}
我的问题是:thread2真的需要保护awake
的作业吗?在我看来notify_all()
电话应该足够了。如果被操作和检查的数据不仅仅是一个简单的“ok to proceed”标志,我在互斥锁中看到了这个值,但这里看起来有些过分。
第二个问题是在代码片段中询问:为什么Boost文档没有显示在“过程数据”步骤之前解锁thread1中的锁定?
编辑:也许我的问题是:是否有更简洁的构造而不是简历来实现这种等待?
答案 0 :(得分:1)
thread2真的需要保护分配才能唤醒吗?
是。从一个线程修改对象并从另一个线程访问它而不进行同步会产生不确定的行为。即使它只是bool
。
例如,在某些多处理器系统上,写入可能只会影响本地内存;如果没有显式同步操作,其他线程可能永远不会看到更改。
为什么Boost文档没有显示在“流程数据”步骤之前解锁thread1中的锁定?
如果在清除标志之前解锁了互斥锁,则可能会错过另一个信号。
是否有比CV简洁的构造来实现这种等待?
在Boost和标准C ++库中,没有;条件变量足够灵活,可以处理任意共享状态,对于这种简单的情况并不特别过于复杂,所以没有特别需要更简单的东西。
更一般地说,您可以使用信号量或管道在线程之间发送简单信号。
答案 1 :(得分:1)
正式地说,你肯定需要在两个线程中都有锁:如果有任何线程 修改一个对象,多个线程访问它,然后 all 访问必须同步。
在实践中,你可能会在没有锁的情况下逃脱它;它的
几乎可以肯定,notify_all
会发出必要的围栏或
membar指令,以确保内存正确同步。
但为什么要承担风险?
关于unlock
的缺席,这是范围的全部要点
锁定模式:unlock
位于对象的析构函数中,所以
即使异常通过,互斥锁也会被解锁。