c++ - 发生在同一线程中的关系之前

标签 c++ concurrency atomic stdatomic

我正在阅读“C++ Concurrency in Action”一书关于 C++ 内存模型的第 5.3 节,下面的 list 5.5 让我感到困惑:

std::atomic<bool> x,y;
std::atomic<int> z;
void write_x_then_y()
{
   // Is there a Happens-Before relationship for statement (1) and (2) below?
   x.store(true,std::memory_order_relaxed); // --> (1)
   y.store(true,std::memory_order_relaxed); // --> (2)
}
void read_y_then_x()
{
   while(!y.load(std::memory_order_relaxed));
   if(x.load(std::memory_order_relaxed))
   ++z;
}

int main()
{
    x=false;
    y=false;
    z=0;
    std::thread a(write_x_then_y);         std::thread b(read_y_then_x);
    a.join();
    b.join();
    assert(z.load()!=0);
}

让我感到困惑的是函数 void write_x_then_y()。作者说“这次 main() 末尾的断言可以触发”并且原子变量 x 上的语句 (1) 与关于原子变量 y 的语句 (2)。但我认为对于 std::memory_order_relaxed不同 原子变量之间没有同步,编译器/CPU 可以在不违反程序语义的情况下重新排序这两个语句。

The happensbefore relationships from listing 5.5 are shown in figure 5.4, along with a possible outcome. enter image description here

最佳答案

一个评估先于另一个评估也发生在它之前。

Sequenced-before 是同一线程中的评估之间的关系,并且独立于同步机制,例如具有非松弛内存顺序的原子加载/存储。

Happens-before 只是通过合并线程间的同步机制将评估顺序的sequenced-before 关系从单线程情况扩展到多线程情况。

参见 https://en.cppreference.com/w/cpp/atomic/memory_order以获得确切的定义。

在另一个语句之前的一个语句中的求值总是先于后者。 (基本上在两个语句之间有一个序列点,尽管自 C++11 以来不再使用该术语。)


编译器可以重新排序这两个松散存储。不过,这并不影响happens-before 关系。仅仅因为两个存储(在不同的原子上)先于彼此并不意味着存储不能被另一个线程以不同的顺序观察,如图中的示例所示。

您需要在加载和存储之间建立先发生 关系,以防止出现所示结果。并且需要以某种方式进行线程间排序,例如通过释放/获取原子操作。基本上,您需要在图中的灰色框之间建立一些箭头。

关于c++ - 发生在同一线程中的关系之前,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72843313/

相关文章:

c# - .NET并发问题: Can I yield a semaphore to another thread

multithreading - C++原子内存顺序与线程事件,例如notify()

c++ - 为什么允许 std::atomic_{char,schar,etc.} typedef 是 std::atomic<T> 基类的类型定义,而不仅仅是 atomic<T>?

c++ - C4700 : uninitialized local variable

c++ - 排序算法是什么(以及它在 GPU 上运行的效率如何)

c++ - 对于 C++ 中的单个静态变量,是否有比类更好的选择?

java 并发实践 16.7

java - CopyOnWriteArrayList迭代器与多线程不一致?

java - 变量读写的原子性

C++ 运算符 << (void*)