【发布时间】:2022-01-02 07:27:06
【问题描述】:
该标准定义了几个“发生在之前”的关系,这些关系将旧的“顺序之前”扩展到多个线程:
[intro.races]11 评估 A 只发生在评估 B 之前
(11.1) — A 在 B 之前排序,或者
(11.2) — A 与 B 同步,或者
(11.3) — A 简单地发生在 X 之前,X 简单地发生在 B 之前。[注10:在没有消费操作的情况下,发生在之前和简单地发生在之前的关系是相同的。 ——尾注]
12 评估 A 强烈发生在评估 D 之前
(12.1) — A 在 D 之前排序,或者
(12.2) — A 与 D 同步,A 和 D 都是顺序一致的原子操作 ([atomics.order]),或
(12.3) — 存在评估 B 和 C,使得 A 在 B 之前排序,B 只是在 C 之前发生,C 在 D 之前排序,或者
(12.4) - 有一个求值 B 使得 A 强烈地发生在 B 之前,而 B 强烈地发生在 D 之前。[注 11:非正式地,如果 A 强烈地发生在 B 之前,那么 A 似乎在所有情况下都在 B 之前被评估。强烈发生在排除消费操作之前。 ——尾注]
(我的粗体字)
两者之间的差异似乎非常微妙。 “强烈发生在之前”对于匹配对或发布-获取操作(除非两者都是 seq-cst)永远不会成立,但它在某种程度上仍然尊重发布-获取同步,因为操作在发布之前排序在匹配获取之后排序的操作“强烈发生在”之前。
为什么这种差异很重要?
“强烈发生在之前”是在 C++20 中引入的,在 C++20 之前,“简单地发生在之前”曾经被称为“强烈发生在之前”。为什么要介绍它?
[atomics.order]/4 表示所有 seq-cst 操作的总顺序与 'strongly occurred before' 一致。
这是否意味着它与“只是发生在之前”不一致?如果是,为什么不呢?
我忽略了简单的“发生在之前”,因为它与“仅发生在之前”的区别仅在于它对 memory_order_consume 的处理,使用 temporarily discouraged,因为显然大多数(全部?)主要编译器将其视为memory_order_acquire。
我已经看过this Q&A,但它没有解释为什么存在“强烈发生之前”,也没有完全说明它的含义(它只是声明它不尊重发布-获取同步,并非完全如此)。
发现 the proposal 介绍了“只是发生在之前”。
我不完全理解,但解释如下:
- “强烈发生在之前”是“仅发生在之前”的弱化版本。
- 只有当 seq-cst 与 aqc-rel 在同一个变量上混合时才能观察到差异(我认为,这意味着当获取负载从 seq-cst 存储读取值时,或者当 seq-cst 负载读取来自发布存储的值)。但我仍不清楚将两者混合的确切效果。
【问题讨论】:
标签: c++ multithreading concurrency language-lawyer c++20