原子操作的 C++11 内存排序参数指定了排序约束。如果您使用 进行存储std::memory_order_release
,并且来自另一个线程的加载读取该值,则来自第二个线程的后续读取操作将看到第一个线程在存储释放之前或之后std::memory_order_acquire
存储到任何内存位置的任何值存储到任何这些内存位置。
如果存储和后续加载都是,std::memory_order_seq_cst
那么这两个线程之间的关系是相同的。您需要更多线程才能看到差异。
例如std::atomic<int>
变量x
和y
,最初都是 0。
线程 1:
x.store(1,std::memory_order_release);
线程 2:
y.store(1,std::memory_order_release);
线程 3:
int a=x.load(std::memory_order_acquire); // x before y
int b=y.load(std::memory_order_acquire);
线程 4:
int c=y.load(std::memory_order_acquire); // y before x
int d=x.load(std::memory_order_acquire);
x
正如所写,与和的存储之间没有关系y
,因此很可能在线程 3 和线程4 中看到a==1
,和。b==0
c==1
d==0
如果所有内存排序都更改为,std::memory_order_seq_cst
则这将强制存储之间的排序为x
和y
。因此,如果线程 3 看到a==1
然后b==0
那意味着 store tox
必须在 store to 之前y
,所以如果线程 4 看到c==1
,意味着 store toy
已经完成,那么 store tox
也必须完成,所以我们必须有d==1
。
实际上,std::memory_order_seq_cst
根据您的编译器和处理器体系结构,在任何地方使用都会增加加载或存储或两者的额外开销。例如,x86 处理器的一种常用技术是使用XCHG
指令而不是存储MOV
指令std::memory_order_seq_cst
,以提供必要的排序保证,而对于std::memory_order_release
普通的MOV
就足够了。在具有更宽松内存架构的系统上,开销可能更大,因为普通加载和存储的保证更少。
内存排序很难。在我的书中,我几乎用了整整一章来讲述它。