- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我现在正在学习C++11 memory order model并想了解 memory_order_relaxed
和 memory_order_consume
之间的区别。
具体来说,我正在寻找一个无法将 memory_order_consume
替换为 memory_order_relaxed
的简单示例。
有一个优秀的post它详细阐述了一个简单但非常具有说明性的示例,其中可以应用 memory_order_consume
。以下是文字复制粘贴。
例子:
atomic<int*> Guard(nullptr);
int Payload = 0;
制作人:
Payload = 42;
Guard.store(&Payload, memory_order_release);
消费者:
g = Guard.load(memory_order_consume);
if (g != nullptr)
p = *g;
我的问题由两部分组成:
memory_order_consume
替换为 memory_order_relaxed
?memory_order_consume
不能替换为 memory_order_relaxed
?最佳答案
没有。memory_order_relaxed
完全不强加任何内存顺序:
Relaxed operation: there are no synchronization or ordering constraints, only atomicity is required of this operation.
虽然 memory_order_consume
对数据相关读取(在当前线程上)强加内存排序
A load operation with this memory order performs a consume operation on the affected memory location: no reads in the current thread dependent on the value currently loaded can be reordered before this load.
编辑
一般memory_order_seq_cst
强memory_order_acq_rel
强memory_ordering_relaxed
。
这就像有一部电梯 A 可以举起 800 公斤的电梯 C 可以举起 100 公斤。
现在,如果你有能力神奇地将电梯 A 变成电梯 C,如果前者挤满了 10 个平均体重的人,会发生什么?那会很糟糕。
要准确了解代码可能出现的问题,请考虑您问题中的示例:
Thread A Thread B
Payload = 42; g = Guard.load(memory_order_consume);
Guard.store(1, memory_order_release); if (g != 0)
p = Payload;
此代码段旨在循环,两个线程之间没有同步,只有排序。
使用memory_order_relaxed
,并假设自然词加载/存储是原子的,代码将等同于
Thread A Thread B
Payload = 42; g = Guard
Guard = 1 if (g != 0)
p = Payload;
从 CPU 的角度来看,线程 A 有两个存储到两个单独的地址,因此如果 Guard
与另一个处理器的 CPU“更近”(意味着存储将完成得更快),它似乎线程 A 正在执行
Thread A
Guard = 1
Payload = 42
而且这个执行顺序是可以的
Thread A Guard = 1
Thread B g = Guard
Thread B if (g != nullptr) p = Payload
Thread A Payload = 42
这很糟糕,因为线程 B 读取了一个未更新的 Payload 值。
然而,在线程 B 中,同步似乎是无用的,因为 CPU 不会像这样重新排序
Thread B
if (g != 0) p = Payload;
g = Guard
但它确实会。
从它的角度来看,有两个不相关的负载,一个确实在依赖数据路径上,但 CPU 仍然可以推测性地完成负载:
Thread B
hidden_tmp = Payload;
g = Guard
if (g != 0) p = hidden_tmp
可能会生成序列
Thread B hidden_tmp = Payload;
Thread A Payload = 42;
Thread A Guard = 1;
Thread B g = Guard
Thread B if (g != 0) p = hidden_tmp
糟糕。
总的来说,这是永远做不到的。
当您要在加载的值和需要对其访问进行排序的值之间生成地址依赖性时,您可以将 memory_order_acquire
替换为 memory_order_consume
。
理解memory_order_relaxed
可以引用ARM架构。
ARM 体系结构仅要求弱内存排序,这意味着通常程序的加载和存储可以任何顺序执行。
str r0, [r2]
str r0, [r3]
在存储到 [r2]
1 之前,可以从外部观察到存储到 [r3]
的代码段。
然而,CPU 并没有达到 Alpha CPU 的水平,并强加了 two kinds of dependencies : address dependency,当内存中的值加载用于计算另一个加载/存储的地址时,以及 control dependency,当内存中的值加载用于计算时另一个加载/存储的控制标志。
在存在这种依赖性的情况下,两个内存操作的顺序保证为 visible in program order :
If there is an address dependency then the two memory accesses are observed in program order.
因此,虽然 memory_order_acquire
会生成内存屏障,但使用 memory_order_consume
时,您是在告诉编译器您使用加载值的方式会生成地址依赖性因此,如果与架构相关,它可以利用这一事实并省略内存屏障。
1 如果r2
是一个同步对象的地址,那就不好了。
关于C++11:memory_order_relaxed 和 memory_order_consume 的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38280633/
从链接: What is the difference between load/store relaxed atomic and normal variable? 这个回答给我留下了深刻的印象: U
我正在查看有关原子操作和发生前关系的 Boost 示例,但我有点困惑。在“通过发布和消费发生之前”部分,有以下示例,他们说这是错误的,但我看不到: atomic a(0); complex_data_
我有一个关于 GCC-Wiki article 的问题.在标题“Overall Summary”下,给出了以下代码示例: 线程 1: y.store (20); x.store (10); 线程 2:
我正在阅读 C++ Concurrency in Action安东尼·威廉姆斯。目前我在他描述 memory_order_consume 的地方。 在那 block 之后有: Now that I’v
我现在正在学习C++11 memory order model并想了解 memory_order_relaxed 和 memory_order_consume 之间的区别。 具体来说,我正在寻找一个无
在试图理解如何处理无锁代码的过程中,我尝试编写一个单一消费者/单一生产者无锁队列。一如既往,我检查了论文、文章和代码,特别是考虑到这是一个有点微妙的主题。 所以,我在 Folly 库中偶然发现了这个数
我是一名优秀的程序员,十分优秀!