繁体   English   中英

std::condition_variable 内存写入可见性

[英]std::condition_variable memory writes visibility

std::condition_variable::notify_one()std::condition_variable::notify_all()保证在调用之前当前线程中的非原子内存写入在通知线程中可见?

其他线程做:

{
    std::unique_lock lock(mutex);
    cv.wait(lock, []() { return values[threadIndex] != 0; });
    // May a thread here see a zero value and therefore start to wait again?
}

主线程执行:

fillData(values); // All values are zero and all threads wait() before calling this.
cv.notify_all(); // Do need some memory fence or lock before this
                 // to ensure that new non-zero values will be visible
                 // in other threads immediately after waking up?

notify_all() 不存储一些原子值从而强制执行内存排序吗? 我没有澄清。

UPD :根据 Superlokkus 的回答和这里的回答:我们必须获取一个锁以确保其他线程中的内存写入可见性(内存传播),否则在我的情况下线程可能会读取零值。

我也错过了这里关于 condition_variable 的引用,它专门回答了我的问题。 在修改必须立即可见的情况下,甚至必须在锁下修改原子变量。

即使共享变量是原子的,也必须在互斥锁下进行修改,才能将修改正确发布到等待线程。

我猜您正在混淆所谓的原子值的内存排序和基于锁的经典同步机制。

当你有一个在线程之间共享的数据时,比如说一个int ,一个线程不能简单地读取它,而另一个线程可能同时写入它。 否则我们就会有数据竞赛。

为了长时间解决这个问题,我们使用了经典的基于锁的同步:线程至少共享一个互斥锁和int 要读取或写入任何线程必须先持有锁,这意味着它们在互斥锁上等待。 互斥体被构建,以便它们可以同时发生。 如果一个线程赢得互斥锁,它可以更改或读取int然后应该解锁它,这样其他人也可以读/写。 使用像您使用的条件变量只是为了使“读取器等待写入器更改值”的模式更有效,它们会被 cv 唤醒,而不是定期等待锁定、读取和解锁,这会被称为忙等待。

因此,因为在等待互斥锁之后或在您的情况下,正确地(仍然需要互斥锁)等待条件变量后,您将锁定保持在任何位置,您可以更改int 读者将在作者能够写出新值后读取新值,而不是旧值。 更新:但是,如果必须添加一件事,这也可能是混淆的原因:条件变量受所谓的虚假唤醒的影响。 这意味着即使您写入没有通知任何线程,读取线程可能仍会唤醒,互斥锁被锁定。 因此,您必须检查您的作者是否真的唤醒了您,这通常是由作者通过更改另一个数据来通知这一点来完成的,或者通过使用您已经想共享的相同数据是否合适。 std::condition_variable::wait的 lambda 参数重载只是为了使检查和返回睡眠代码看起来更漂亮一些。 根据你现在的问题,我不知道你是否想在这份工作中使用你的values

但是,“主”线程的代码片段不正确或不完整:您没有在互斥锁上进行同步以更改values 您必须为此持有锁,但可以在没有锁的情况下进行通知。

std::unique_lock lock(mutex);
fillData(values); 
lock.unlock();
cv.notify_all(); 

但是这些基于互斥锁的模式有一些缺点并且速度很慢,一次只有一个线程可以做某事。 这就是所谓的原子,就像std::atomic<int>发挥作用。 它们可以同时被多个线程同时写入和读取,而无需互斥锁。 内存排序只是一个需要考虑的事情,并且对于您以有意义的方式使用其中几个或者您不需要“写入后,我永远不会看到旧值”保证的情况进行优化。 但是,使用它的默认内存排序memory_order_seq_cst您也可以。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM