众所周知,自 C++11 以来,有 6 个内存顺序,并且在文档中编写了以下内容std::memory_order_acquire
:
memory_order_acquire
具有此内存顺序的加载操作在受影响的内存位置上执行获取操作:在此加载之前,当前线程中的内存访问不能重新排序。这确保了释放相同原子变量的其他线程中的所有写入在当前线程中都是可见的。
1.非原子加载可以在atomic-acquire-load之后重新排序:
即它不保证非原子加载不能在获取原子加载之后重新排序。
static std::atomic<int> X;
static int L;
...
void thread_func()
{
int local1 = L; // load(L)-load(X) - can be reordered with X ?
int x_local = X.load(std::memory_order_acquire); // load(X)
int local2 = L; // load(X)-load(L) - can't be reordered with X
}
加载int local1 = L;
后可以重新排序X.load(std::memory_order_acquire);
吗?
2. 我们可以认为,在 atomic-acquire-load 之后,non-atomic-load 不能重新排序:
一些文章包含一张图片,展示了获取-释放语义的本质。这很容易理解,但可能会引起混乱。
例如,我们可能认为std::memory_order_acquire
不能重新排序任何一系列的 Load-Load 操作,即使是非原子加载也不能在 atomic-acquire-load 之后重新排序。
3.非原子加载可以在atomic-acquire-load之后重新排序:
澄清的好处是:获取语义可防止读取-获取的内存重新排序,并以程序顺序跟随它的任何读取或写入操作。http://preshing.com/20120913/acquire-and-release-semantics/
但也知道:在强排序系统(x86、SPARC TSO、IBM 大型机)上,对于大多数操作来说,发布-获取排序是自动的。
第 34 页的 Herb Sutter 显示:https ://onedrive.live.com/view.aspx?resid=4E86B0CF20EF15AD!24884&app=WordPdf&authkey=!AMtj_EflYn2507c
4. 即再次,我们可以认为在 atomic-acquire-load 之后 non-atomic-load 不能重新排序:
即对于 x86:
- 对于大多数操作,release-acquire 排序是自动的
- 读取不会与任何读取一起重新排序。(任何 - 即无论是否年龄较大)
那么可以在 C++11 中的 atomic-acquire-load 之后重新排序 non-atomic-load 吗?