C++中的内存模型:顺序一致性和原子性

9

5
好的,请问您有什么需要翻译的内容吗?每个问题请提出一个问题。 - MrEricSir
3个回答

12
如果你使用带有适当内存顺序的原子操作来保证顺序一致性,则 C++ 内存模型可以保证顺序一致性。如果你只使用普通的非原子操作或者放松了的原子操作,并且没有互斥锁,那么就不能保证顺序一致性。
编译器可以重新排序操作,只要行为上看不出差别就可以,这就是所谓的 as-if 规则。例如,如果重新排序顺序一致的原子操作会产生不同的可观察结果,那么它就不符合 as-if 规则;如果不会产生不同的可观察结果,那么重新排序是允许的。

1
更新,幻灯片没有问题,所以我删除了之前的评论。请看我的回答,我认为他们的意思是什么。然而,一个幻灯片不应该让你怀疑所有其他证据,表明C++的默认软件内存模型是弱松散的,这包括无数网页和编译器的实际行为。 - Peter Cordes
太棒了!编译器是否允许以顺序一致的方式重新排序原子操作? - choxsword
@Olumide 一般情况下无法检测数据竞争,因此编译器不需要检测它们。数据竞争是未定义行为,因此编译器可以假设它们永远不会发生,而你的工作就是避免它们(例如通过使用原子操作来访问任何共享数据)。我不知道你所说的“回退添加栅栏”的意思。这听起来像是你应该提出自己的问题,而不是试图在这里抢占评论区提出新问题。 - Jonathan Wakely
@JonathanWakely 我也这么认为,关于检测竞争的能力。我刚刚读到了有关无竞争程序的顺序一致性的内容,其中编译器添加栅栏以保留顺序一致性的外观。这让我想知道如果确实存在竞争会发生什么。我猜短答案是所有的赌注都没有了。(我现在停止抢线程了) - Olumide

6
我觉得我从之前的幻灯片中读懂了这张幻灯片在讲什么:
幻灯片12: 顺序一致性 [Leslie Lamport, 1979] 任何执行的结果都与以下情况相同 1. 所有线程的操作按某个顺序执行 2. 每个线程的操作在程序指定的顺序中出现
幻灯片14: 数据竞争自由的顺序一致性 SC-DRF: 1. 我们确保程序不包含数据竞争 2. 系统保证执行是顺序一致的
因此,在第29张幻灯片上,作者说一旦你使用std::atomic避免数据竞争UB,程序运行就好像所有事情都按程序顺序发生。 (如果所有的std::atomic操作都使用默认的memory_order_seq_cst)。
这是一个有趣的看待C++弱(对于非原子对象)内存模型的方式。这看起来是一组很好的幻灯片。SC原子操作是强有序的,并且在非原子操作中有点像单向障碍。(如果您有任何松散的原子操作)
请注意,无数据竞争意味着您不能在任意时间查看非原子变量,只能在您已经确定没有其他线程正在写入它们时才能查看它们。(通常通过一个与写入者完成的释放存储所看到的获取负载的同步关系或互斥锁。)这里的无数据竞争部分是关键;如果您不小心,很容易出现数据竞争UB。在为实际CPU编译成汇编代码时,这意味着非原子访问可以像正常情况下一样工作,而atomic<T> seq_cst访问需要阻止编译时和运行时重新排序。 https://preshing.com/20120625/memory-ordering-at-compile-time/ 第二部分:请不要养成一次询问两个非常不同问题的习惯。
这个“CPU是如何做到的?”的问题更适合作为您稍后的问题的一部分:Atomicity on x86 我已经写好了大部分答案,我会把它放在那里。

这里显然的问题是,只有避免未定义行为(UB)才能实现数据竞争自由;但是避免UB仅对顺序程序有明确定义。因此,顺序一致性依赖于程序的顺序解释。所以整个事情都没有明确定义! - curiousguy

-6
唯一可能为具有未定义行为的语言定义语义的方法是通过描述顺序执行。因此,所有程序都像顺序执行一样运行,或者没有一个程序有定义行为。
在C/C++中同时拥有这两种方式的想法是一种骗局。程序必须按顺序运行才能使语义有意义。

人们不同意我的看法,然而没有人提出过没有顺序一致性的C/C ++语义解释。 - curiousguy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接