>

Memory Model(C++)

Acquire 与 Release 语义

对于 Acquire 来说,保证 Acquire 后的读操作不会发生在 Acquire 动作之前
对于 Release 来说,保证 Release 前的写操作不会发生在 Release 动作之后

X86-64中Load读操作本身满足Acquire语义,Store写操作本身也是满足Release语义。但Store-Load操作间等于没有保护,因此仍需要靠mfence或lock等指令才可以满足到Synchronizes-with规则。

内存一致性模型 Memory Model

内存一致性模型从程序员视角,由内存序Memory Ordering和写操作原子性Store Atomicity来定义,针对不同线程中原子操作的全局顺序:

Strong Consistency / Sequential consistency 顺序一致性
Release Consistency / release-acquire / release-consume
Relaxed Consistency

C++11相应定义了6种内存模型:

std::memory_order_seq_cst 所有读写操作不能跨过,写顺序全线程可见
std::memory_order_acq_rel 所有读写操作不能跨过,写顺序仅同步线程间可见、
std::memory_order_release 所有读写操作不能往后乱序、
std::memory_order_acquire 所有读写操作不能向前乱序、
std::memory_order_consume 依赖该读操作的后续读写操作不能向前乱序
std::memory_order_relaxed 无特殊要求

C++ 中 voldatile 等于插入编译器级别屏障,因此并不能阻止 CPU 硬件级别导致的重排。C++11 中 volatile 语义没有任何变化,不过提供了 std::atomic 工具可以真正实现原子操作,而且默认加入了内存屏障(可以通过在 store 与 load 操作时设置内存模型参数进行调整,默认为 std::memory_order_seq_cst)。

C++ 实践中推荐涉及并发问题都使用 std::atomic,只有涉及特殊内存操作的时候才使用 volatile 关键字。这些情况通常 IO 相关,防止相关操作被编译器优化,也是 volatile 关键字发明的本意。

可参考:
https://zhuanlan.zhihu.com/p/55901945