【问题标题】:Effect of std::memory_order_acq_rel on non-atomic variable read in other threadstd::memory_order_acq_rel 对其他线程中读取的非原子变量的影响
【发布时间】:2015-09-16 06:46:15
【问题描述】:

我想我主要了解 C++ 原子库中各种 memory_order 标志的语义。

但是,我对以下情况感到困惑:

假设我们有两个线程 - 线程 A 是“主执行”线程,线程 B 是线程池中的任意线程,可以在其中调度和运行任务。

如果我使用std::memory_order_acq_rel 执行“读-写-更新”原子操作,然后在布尔变量上执行非原子写入,则 非原子 em> 写立即对其他线程可见?我认为答案是否定的,除非其他线程也访问执行“读写更新”操作的 atomic 变量。

因此,例如,给定一个全局 std::atomic_flag 变量 X、一个全局 bool 值 B,以及一个线程池对象 THREADPOOL,它有一个成员函数 dispatch,它将执行任意函数处理程序在另一个线程中:

if (!X.test_and_set(std::memory_order_acq_rel)
{
   if (SOME_CONDITION) B = true;
   THREADPOOL.dispatch([]() { 
      // This executes in Thread B
      if (B) { /* do something */ } // are we guaranteed to see changes to B?
   });
}

所以在本例中,lambda 函数内的代码将在不同的线程中执行。该线程是否一定会在第一个线程中看到对B 的(非原子)更新?请注意,第二个线程访问 atomic_flag,所以我的理解是,对B 的更改将一定会在第二个线程中看到。

我的理解正确吗?如果是这样,使用std::memory_order_seq_cst 会改变吗?

【问题讨论】:

    标签: c++ multithreading c++11 atomic


    【解决方案1】:

    THREADPOOLdispatch 方法的正确实现应提供 happens-before 在此方法调用之前 调用者 执行的所有操作与函数执行的所有操作之间的关系(在您的情况下为 lambda ),传递给方法。

    所以,执行你的 lambda 函数的辅助线程肯定会看到由主线程分配的 B 的值。

    如果没有发生前的顺序,保证变量修改立即可见的唯一方法是使用std::memory_order_seq_cst 进行修改和读取。参见,例如,this question

    【讨论】:

    • 当您需要memory_order_seq_cst 时,您几乎在所有事情上都需要它。这意味着你只能使用原子变量(这些只能在线程启动之前创建)。
    【解决方案2】:

    没有内存顺序规范使未来的内存访问可见。最多,它们会阻止它们在原子访问可见之前变得可见。

    如果您想确保特定访问确实变得可见,您必须对该访问强制执行特定的内存排序,或者您必须拥有使用内存排序的未来访问,以确保它在您想要使其可见的访问之后排序.

    所有原子操作都是原子的。内存排序只允许你做三件事:

    1. 建立此原子操作相对于先前操作(无论是否为原子)的排序 - 此操作保证在它们之后。

    2. 针对未来的操作(无论是否为原子操作)确定此操作的顺序 - 保证此操作在它们之前。

    3. 使用其他原子操作建立排序。

    这些都不能确保未来的非原子操作“很快”发生或在任何特定时间变得可见。

    【讨论】:

    • 我回答了一半的问题。 Tsyvarev 回答了另一半。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-07
    • 2015-08-13
    • 1970-01-01
    • 1970-01-01
    • 2017-02-28
    相关资源
    最近更新 更多