当 3 "stores" 依次发生并且只有一个是原子时会发生什么

What occurs when 3 "stores" happen sequentially and only one is atomic

为了清楚起见,我试图将其归结为一个简单的示例。我有各种各样的原子标志,用于指示一件事刚刚完成而另一件事尚未开始。这两件事都涉及将数据存储在缓冲区中。我试图弄清楚 rusts 发布排序的具体工作原理,以便了解如何执行此操作。考虑 "very oversimplified" 示例:

use std::sync::atomic::{AtomicU32,Ordering};

fn main(){
    let mut a = 0;
    let mut b = AtomicU32::new(0);
    let mut c = 0;

    // stuff happens

    a = 10;
    b.store(11,Ordering::Release);
    c = 11;
}

特别是,必须保持类型不变,即变量 b 的原子存储发生在 a 之后和 c 之前,但这些变量或其存储操作实际上都不是原子的(是的,在示例中他们可以,但这是针对 simplification/visualization) 的。如果可以的话,我想避免使用互斥体(我不想用为什么来转移问题的注意力)。

当我阅读 Release 排序时,它强烈表明对变量 "a" 的赋值必须在存储到 b:

之前发生

When coupled with a store, all previous operations become ordered before any load of this value with Acquire (or stronger) ordering. In particular, all previous writes become visible to all threads that perform an Acquire (or stronger) load of this value. Notice that using this ordering for an operation that combines loads and stores leads to a Relaxed load operation! This ordering is only applicable for operations that can perform a store. Corresponds to memory_order_release in C++20.

但是,它不能保证在存储到变量 b 之前不能移动对变量 c 的赋值。我读到的几乎所有内容总是说 stores/loads 在原子操作之前保证发生之前,但不保证跨边界向另一个方向移动操作。

如果使用 Release 排序,我担心变量 c 的赋值可能会在存储到 b 之前移动,我是否正确?

我查看了其他问题,例如 Which std::sync::atomic::Ordering to use? 和其他类似的堆栈溢出问题,但据我所知,它们没有涵盖是否可以使用 release 将 c 移动到 b 之前。

回答我自己的问题:是的,我应该担心对 C 的分配可能会在 B 之前重新排序,因为 "Release" 排序只会阻止 A 移过 B。通过使用 Release 设置围栏在 B 和 C 的分配之间排序,我可以进一步防止 C 在 B 之前重新排序(因为它会阻止 B 在 C 之后,这是一回事)。

所有这些都适用于 CPU store/load 排序。原子存储和栅栏是否阻止编译器也移动这些操作取决于编译器,应查阅其文档。