9

正如我们从 C11-memory_order 中了解到的:http: //en.cppreference.com/w/c/atomic/memory_order

与 C++11-std::memory_order 相同:http ://en.cppreference.com/w/cpp/atomic/memory_order

在强排序系统(x86、SPARC、IBM 大型机)上, 发布-获取排序是自动的。此同步模式不会发出额外的 CPU 指令,仅会影响某些编译器优化(例如,禁止编译器将非原子存储移动到原子存储释放之后或在原子加载获取之前执行非原子加载)

但是对于 x86-SSE 指令来说这是真的吗(除了 [NT] - 非临时的,我们总是必须使用 L/S/MFENCE)吗?

这里说,“sse 指令......对向后兼容性没有要求,并且内存顺序未定义”。人们认为,当需要时,为了与旧版本的处理器 x86 兼容而保留了严格的可排序性,但是新命令,即 SSE([NT] 除外) - 自动剥夺了释放-获取命令,是吗?

4

2 回答 2

9

以下是英特尔软件开发人员手册第 3 卷第 8.2.2 节(2014 年 9 月版本 325384-052US)的摘录:

  • 读取不会与其他读取重新排序。
  • 写入不会与较旧的读取一起重新排序。
  • 对内存的写入不会与其他写入一起重新排序,但以下情况除外:
    • 使用 CLFLUSH 指令执行的写操作;
    • 使用非临时移动指令(MOVNTI、MOVNTQ、MOVNTDQ、MOVNTPS 和 MOVNTPD)执行的流式存储(写入);和
    • 字符串操作(参见第 8.2.4.1 节)。
  • 对不同位置的旧写入可能会重新排序读取,但对同一位置的旧写入则不会。
  • 不能使用 I/O 指令、锁定指令或序列化指令重新排序读取或写入。
  • 读取不能通过较早的 LFENCE 和 MFENCE 指令。
  • 写入不能通过更早的 LFENCE、SFENCE 和 MFENCE 指令。
  • LFENCE 指令不能通过较早的读取。
  • SFENCE 指令不能通过较早的写入。
  • MFENCE 指令不能传递较早的读取或写入。

前三个项目符号描述了发布-获取顺序,并且在那里明确列出了例外情况。如您所见,只有可缓存性控制指令 ( MOVNT*) 在异常列表中,而 SSE/SSE2 和其他向量指令的其余部分遵循一般内存排序规则,并且不需要使用[LSM]FENCE.

于 2014-12-04T19:59:06.000 回答
2

确实,正常的1 SSE 加载和存储指令,以及使用内存源操作数时的隐含加载,在排序方面与 GP 寄存器的正常加载和存储具有相同的获取释放行为。

但是,它们通常不能std::memory_order_acquire直接用于对大于 8 字节的对象实现或std::memory_order_release操作,std::atomic因为不能保证大于 8 字节的 SSE 或 AVX 加载和存储的原子性。缺失的保证不仅仅是理论上的:有几种实现(包括 AMD 的 Ryzen 等全新的实现)将大负载或存储分成两个较小的负载。


1即,那些未在已接受答案的例外列表中列出的:NT 存储clflush和字符串操作。

于 2017-09-01T16:32:05.530 回答