为什么我需要获取一个锁来修改共享" atomic"通知condition_variable之前的变量

时间:2017-01-26 05:07:08

标签: c++ c++11 condition-variable

收到cppreference.com

  

打算修改变量的线程必须

     
      
  1. 获取std :: mutex(通常通过std :: lock_guard)
  2.   
  3. 在锁定时执行修改
  4.   
  5. 在std :: condition_variable上执行notify_one或notify_all(不需要保留锁通知)
  6.         

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

我不太明白,为什么修改原子变量需要锁定。请参阅以下代码段:

public function create()
{
    $tenants = Tenant::all();
    $categories = Category::all();
    return view('items.create', ['categories' => $categories, 'tenants' => $tenants]);
}

在PushEvent函数中,我没有获取s_mtx,因为s_hasEvent是一个原子变量而队列是无锁的。没有获得s_mtx锁定的问题是什么?

2 个答案:

答案 0 :(得分:6)

Yakk's answer to the question you linked to所述,它是为了防止这一系列事件导致错过唤醒:

    1. 线程A锁定互斥锁。
    1. 线程A调用lambda的闭包,它执行m_hasEvents.load(std::memory_order_relaxed);并返回值false
    1. 线程A被调度程序中断,线程B开始运行。
    1. 线程B将事件推入队列并存储到s_hasEvent
    1. 主题B运行s_cv.notify_one()
    1. 线程B被调度程序中断,线程A再次运行。
    1. 线程A评估闭包返回的false结果,确定没有挂起事件。
    1. 线程A条件变量上的块,等待事件。

这意味着错过了notify_one()调用,即使队列中有事件准备就绪,条件变量也会阻塞。

如果在互斥锁被锁定时完成对共享变量的更新,那么步骤4在第2步和第7步之间不可能发生,因此条件变量检查事件得到了一致的结果。使用发布者和消费者使用的互斥锁,商店到s_hasEvent发生在步骤1之前(因此闭包加载值true并且永远不会阻塞条件变量)或者它发生在步骤8之后(所以notify_one()电话会唤醒它。)

答案 1 :(得分:1)

找到关于此问题in another thread的非常好的解释。

获取战利品
  

下面提到有关种族状况的问题。

     

如果传达的数据是原子的,那么我们就可以在没有互联网的情况下发送"发送"侧?

最后。