我现在正在学习C++ 11内存阶模型,并想明白之间的差别memory_order_relaxed和memory_order_consume.
具体而言,我正在寻找一个简单的例子,其中一个不能代替memory_order_consume用memory_order_relaxed.
有一篇很好的文章详细阐述了一个memory_order_consume可以应用的简单但非常具有说明性的例子.下面是文字复制粘贴.
例:
atomic<int*> Guard(nullptr);
int Payload = 0;
Run Code Online (Sandbox Code Playgroud)
制片人:
Payload = 42;
Guard.store(&Payload, memory_order_release);
Run Code Online (Sandbox Code Playgroud)
消费者:
g = Guard.load(memory_order_consume);
if (g != nullptr)
p = *g;
Run Code Online (Sandbox Code Playgroud)
我的问题包括两部分:
memory_order_consume用memory_order_relaxed在上面的例子?memory_order_consume不能被替换memory_order_relaxed?我在这篇SO帖子中阅读了 [[carries_dependency]] 。
但我无法理解的是接受的答案中的以下句子:
“特别是,如果将使用 memory_order_consume 读取的值传递给函数,然后没有 [[carries_dependency]],那么编译器可能必须发出内存栅栏指令以保证支持适当的内存排序语义。如果参数用 [[carries_dependency]] 注释,那么编译器可以假设函数体将正确携带依赖项,并且可能不再需要此围栏。
类似地,如果一个函数返回一个加载了 memory_order_consume 的值,或者从这样的值派生,那么如果没有 [[carries_dependency]],编译器可能需要插入一个栅栏指令来保证适当的内存排序语义得到支持。有了 [[carries_dependency]] 注释,这个围栏可能不再是必要的,因为调用者现在负责维护依赖树。”
让我们一步一步来:
“如果将使用 memory_order_consume 读取的值传递给函数,然后没有 [[carries_dependency]],那么编译器可能必须发出内存栅栏指令,以确保支持适当的内存排序语义。”
因此,对于释放-消耗内存模型中的原子变量,当原子变量作为参数传递给函数时,编译器将引入栅栏硬件指令,以便它始终具有提供给函数的原子变量的最新和更新值。
下一个 -
“如果参数用 [[carries_dependency]] 注释,那么编译器可以假设函数体将正确携带依赖项,并且可能不再需要这个围栏。”
这让我很困惑 - 原子变量值已经被消耗了,然后函数携带了什么依赖?
相似地 -
“如果一个函数返回一个加载了 memory_order_consume 的值,或者从这样的值派生,那么如果没有 [[carries_dependency]],编译器可能需要插入一个栅栏指令来保证适当的内存排序语义得到支持。使用 [[ Carry_dependency]] 注释,这个围栏可能不再是必要的,因为调用者现在负责维护依赖树。”
从这个例子中,它不清楚它试图说明携带依赖的意义是什么?