有人能用一种凡人理解的语言解释它吗?
我现在正在学习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?我知道这memory_order_consume已被弃用,但我试图理解原始设计中的逻辑以及如何工作[[carries_dependency]]以及kill_dependency应该如何工作。为此,我想要一个在 IBM PowerPC 或 DEC alpha 上中断的具体代码示例,甚至是一个假设的架构,该架构具有一个在 C++11 或 C++14 中完全实现消耗语义的假设编译器。
我能想到的最好的例子是这样的:
int v;
std::atomic<int*> ap;
void
thread_1()
{
v = 1;
ap.store(&v, std::memory_order_release);
}
int
f(int *p [[carries_dependency]])
{
return v;
}
void
thread_2()
{
int *p;
while (!(p = ap.load(std::memory_order_consume)))
;
int v2 = f(p);
assert(*p == v2);
}
Run Code Online (Sandbox Code Playgroud)
我知道这段代码中的断言可能会失败。但是,如果您删除from ,断言是否应该失败?如果是这样,为什么会这样呢?毕竟,您请求了 a ,那么为什么您希望其他访问能够反映获取语义呢?如果删除不能使代码正确,那么有什么示例(或为所有变量设置默认值)会破坏正确的代码?[[carries_dependency]]fmemory_order_consumev[[carries_dependency]][[carries_dependency]][[carries_dependency]]
我唯一能想到的是,这也许与寄存器溢出有关?如果函数将寄存器溢出到堆栈上并稍后重新加载它,则可能会破坏依赖链。因此,[[carries_dependency]]在某些情况下可能会使事情变得高效(也就是说在调用此函数之前不需要在调用者中发出内存屏障),但也要求被调用者在任何寄存器溢出或调用另一个函数之前发出内存屏障,这在其他情况下可能效率较低案例?不过,我在这里抓住了救命稻草,所以仍然很想听听了解这些东西的人的意见......
我读过有关携带依赖关系和依赖关系排序之前,在其定义中使用一个5.1.2.4(p16):
在以下情况下,评估
A在评估之前是依赖顺序的B:—
A对原子对象执行释放操作M,并在另一个线程中B执行消耗操作M并读取以 为首的释放序列中的任何副作用写入的值A,或— 对于某些求值
X,A之前是依存顺序X并X带有对 的依存关系B。
所以我试图制作一个可能有用的例子。就这个:
static _Atomic int i;
void *produce(void *ptr){
int int_value = *((int *) ptr);
atomic_store_explicit(&i, int_value, memory_order_release);
return NULL;
}
void *consume(void *ignored){
int int_value = atomic_load_explicit(&i, memory_order_consume);
int new_int_value = int_value + 42;
printf("Consumed = %d\n", new_int_value);
}
int main(int …Run Code Online (Sandbox Code Playgroud) 根据C++标准:
\n\n\n如果 A 的值用作 B 的操作数,则求值 A 具有对求值 B 的依赖性,除非:
\n\xe2\x80\x94 B 是 std::kill_dependency (29.3) 的任何特化的调用,或者
\n\xe2\x80\x94 A 是内置逻辑 AND(&&,参见 5.14)或逻辑 OR(||,参见 5.15)运算符的左操作数,或者
\n\xe2\x80\x94 A 是条件(?:,参见 5.16)运算符的左操作数,或者
\n\xe2\x80\x94 A 是内置逗号 (,) 运算符的左操作数 (5.18);(...)
\n
我可以理解为什么关系之前排序的依赖项会在kill_dependency调用时停止,但是为什么逻辑AND、OR、逗号等运算符也会破坏依赖链?
\n这是否意味着下面的代码有未定义的行为?
\n//thread1\nint y = 2\natomicVal.store(true);\n\n//thread2 \nauto x = atomicVal.load(std::memory_order_consume);\ncout << x && y;\nRun Code Online (Sandbox Code Playgroud)\n