是在实践中有用的释放序列的概念

Is the concept of release-sequence useful in practice?

本文关键字:释放 实践中 有用      更新时间:2023-10-16

c 原子语义仅保证由最后一个线程执行的内存操作的可见性(通过偶然的关系(,该线程执行了释放写入(简单或读取模型 - write(操作。p>考虑

int x, y;
atomic<int> a;

线程1:

x = 1;
a.store(1,memory_order_release);

线程2:

y = 2;
if (a.load(memory_order_relaxed) == 1))
  a.store(2,memory_order_release);

然后,a == 2的观察意味着线程2操作的可见性(y == 2(,而不是线程1(一个人甚至无法读取x(。

据我所知,多线程的真实实现使用了栅栏的概念(有时是发行商店(,但在序列或发行序列之前不进行,这是高级C 概念;我看不到这些概念映射到的真实硬件详细信息。

a中2中的值2时,实际实现如何不保证线程1内存操作的可见性?

换句话说,发布序列定义中有什么好处吗?为什么发行序列不扩展到修改顺序中的每个后续修改?

特别考虑愚蠢的线程3:

if (a.load(memory_order_relaxed) == 2))
  a.store(2,memory_order_relaxed);

愚蠢的线程3可以抑制任何真实硬件的任何可见性保证吗?换句话说,如果Value 2在全球可见,将如何再次使其在全球范围内打破任何订购?

我的真实多处理的心理模型不正确?可以在某些CPU上看到部分可见的值,但请注意另一个值?

(当然,我假设一个放松写作的非疯狂语义,正如及时回到及时的写作,使C 的语言语言绝对是毫无意义的,与诸如Java这样的安全语言不同,它总是具有有限的语义。-Causal放松语义。(

让我们首先回答您的问题:

为什么发行序列不扩展到修改顺序中的每个后续修改?

因为如果是这样,我们将失去一些潜在的优化。例如,考虑线程:

x = 1;                            // #1
a.store(1,memory_order_relaxed);  // #2

根据当前规则,编译器能够重新排序#1和#2。但是,在发布发布序列之后,不允许编译器重新排序这两行,因为另一个线程像线程2这样的线程可能会引入以#2为首并以释放操作为尾声的释放序列,因此有些读取可能会读取 - 另一线程中的操作将与#2同步。


您给出一个特定的例子,并声称所有实施将产生特定的结果,而语言规则不能保证这一结果。这不是问题,因为语言规则旨在处理所有情况,而不仅仅是您的特定示例。当然,语言规则可以得到改进,以便可以保证您的特定示例的预期结果,但这不是一件琐碎的工作。至少,正如我们上面提到的那样,仅扩展发布序列的定义不是一个可接受的解决方案。