【发布时间】:2022-06-10 16:40:20
【问题描述】:
考虑以下情况
// Global
int x = 0; // not atomic
// Thread 1
x = 1;
// Thread 2
if (false)
x = 2;
根据标准,这是否构成数据竞争? [intro.races] 说:
如果其中一个修改了内存位置 (4.4) 而另一个读取 或修改相同的内存位置。
如果程序的执行包含两个潜在的并发冲突操作,则该程序的执行包含数据竞争, 至少其中一个不是原子的,也不会发生在另一个之前,除了特殊情况 下面描述的信号处理程序。任何此类数据竞争都会导致未定义的行为。
从语言律师的角度来看是否安全,因为永远不允许程序执行“表达式评估”x = 2;x = 2;?
从技术角度来看,如果某个奇怪、愚蠢的编译器决定对该写入执行推测执行,在检查实际情况后将其回滚怎么办?
启发这个问题的原因是(至少在标准 11 中),允许以下程序的结果完全取决于重新排序/推测执行:
// Thread 1:
r1 = y.load(std::memory_order_relaxed);
if (r1 == 42) x.store(r1, std::memory_order_relaxed);
// Thread 2:
r2 = x.load(std::memory_order_relaxed);
if (r2 == 42) y.store(42, std::memory_order_relaxed);
// This is allowed to result in r1==r2==42 in c++11
【问题讨论】:
-
哪个体面的编译器会从 if (0) 发出代码?
-
无,但问题被标记为“语言律师”。考虑这个问题:如果编译器没有删除 if(0) foo();然后通过投机执行或任何其他转换导致数据竞争在技术上仍符合合同标准?标准是否强制这种行为,或者它是否属于“未定义行为”,给予任何合规的编译器许可来做任何事情?
-
@Fareanor,Re,“无论如何,代码永远不会被执行。”问题不在于任何理智的实现会做什么。问题在于language-lawyer 认为标准可能允许 实现做什么。 OP 专门询问了一个实现,它开始执行
x=2分配并同时测试if条件,然后在发现条件为假时取消或“回滚”操作。 -
@DanielLangr:也高度相关:What formally guarantees that non-atomic variables can't see out-of-thin-air values and create a data race like atomic relaxed theoretically can? - 凭空出现的问题只是
mo_relaxed形式上的一个差距,而不是这适用于普通对象。 (而且任何真正的实现都不会允许原子操作;C++ 委员会打算禁止它。)引入影响行为的数据竞争将违反 as-if 规则。 (另见lwn.net/Articles/793253)
标签: c++ concurrency language-lawyer memory-model