atomic_thread_fence(acquire) 可以防止之前的加载在其自身之后重新排序吗?

Can atomic_thread_fence(acquire) prevent previous loads being reordered after itself?

我理解 C++ 中的 atomic_thread_fence 与原子 store/loads 完全不同,通过尝试将它们解释为 CPU(可能是 x86)来理解它们并不是一个好习惯的 mfence/lfence/sfence.

如果我使用 c.load(memory_order_acquire)c.load 之后的 stores/loads 不能在 c.load 之前重新排序。但是,我认为在c.load之前对stores/loads没有限制。我的意思是 c.load 之前的一些 stores/loads 理论上可以在它之后重新排序。

但是说到atomic_thread_fence(memory_order_acquire),涉及到3种对象:围栏,围栏前的store/loads和围栏后的store/loads。

我认为栅栏肯定会阻止 store/loads 在这个栅栏在它自己之前重新排序之后,就像原子 store/load 一样。但是它会阻止 store/loads 在这个栅栏被重新排序之前吗?

我认为通过以下搜索答案是肯定的:

  1. preshing's article

    An acquire fence prevents the memory reordering of any read which precedes it in program order with any read or write which follows it in program order.

    所以他没有指定方向。

  2. modernescpp

    there is an additional guarantee with the acquire memory barrier. No read operation can be moved after the acquire memory barrier.

    所以我觉得他直接答应了?

然而,我在 cppreference 中没有找到“官方”答案,它只指定了 fences 和 atomics 在不同线程中如何相互交互。

但我不确定,所以我有这个问题。

在更仔细地阅读你的问题后,看起来你的 modernescpp link 犯了与 Preshing 在 https://preshing.com/20131125/acquire-and-release-fences-dont-work-the-way-youd-expect/ 中揭穿的相同的错误 - fences are 2-way barriers, 否则它们就没用了。

紧随其后的松弛负载至少与获取负载一样强。获取栅栏之后该线程中的任何内容都发生在加载之后,因此它可以与另一个线程中的释放存储(或释放栅栏 + 松弛存储)同步。

But will it prevent store/loads before this fence being reordered after itself?

商店没有,它只是一个收购围栏。

负载,是的。就存在连贯共享 cache/memory 的内存模型而言,我们正在限制对其访问的本地重新排序,获取栅栏会阻止 LoadLoad 和 LoadStore 重新排序。 https://preshing.com/20130922/acquire-and-release-fences/

(这不是 ISO C++ 的形式主义定义事物的方式。它根据发生在规则之前的规则工作,这些规则相对于从存储中看到值的负载排序事物. 在这些术语中,松弛加载后跟获取栅栏可以创建与释放序列的先行关系,因此该线程中的后续代码会看到在另一个线程中存储之前发生的所有事情。)