我一直在读Jeff Preshing关于"关系同步"的这篇文章;发布获取订购";来自cpp引用的std::memory_order页面中的部分,我真的不明白:
按照标准,似乎有某种承诺,我不明白为什么这是必要的。让我们以CPP参考中的示例为例:
#include <thread>
#include <atomic>
#include <cassert>
#include <string>
std::atomic<std::string*> ptr;
int data;
void producer()
{
std::string* p = new std::string("Hello");
data = 42;
ptr.store(p, std::memory_order_release);
}
void consumer()
{
std::string* p2;
while (!(p2 = ptr.load(std::memory_order_acquire)))
;
assert(*p2 == "Hello"); // never fires
assert(data == 42); // never fires
}
int main()
{
std::thread t1(producer);
std::thread t2(consumer);
t1.join(); t2.join();
}
参考资料解释道:
如果线程A中的原子存储被标记为memory_order_release,而线程B中来自同一变量的原子加载被标记为memory_order_aquire,那么从线程A的角度来看,在原子存储之前发生的所有内存写入(非原子和松弛原子(在线程B中都会变成可见的副作用。也就是说,一旦原子加载完成,线程B保证看到线程A写入内存的所有内容。只有当B实际返回A存储的值,或者在发布序列的后面返回一个值时,这个承诺才成立。
据我所知,当我们
ptr.store(p, std::memory_order_release)
我们实际要做的是告诉编译器和CPU,在运行时,使其不可能在ptr
的新值对线程t2可见之后,data
和std::string* p
指向的内存可见。
同样,当我们
ptr.load(std::memory_order_acquire)
我们告诉编译器和CPU:这样ptr
的加载就不会晚于*p2
和data
的加载。
所以我不明白我们还有什么进一步的承诺?
这个ptr.store(p, std::memory_order_release)
(L1(保证,只要其他线程以正确的方式读取ptr
(在本例中,使用std::memory_order_acquire
(,在该特定线程(T1(中该行之前所做的任何事情都将对其他线程可见。此保证仅适用于此对,仅此线不保证任何内容。
现在,在另一个线程(T2(上有ptr.load(std::memory_order_acquire)
(L2(,它与来自另一线程的对一起工作,保证只要它读取T1中写入的值,就可以看到在该行之前写入的其他值(在您的情况下,它是data
(。因此,由于L1与L2同步,data = 42;
发生在assert(data == 42)
之前。
此外,还可以保证ptr
是以原子方式写入和读取的,因为它是原子的。该准则中没有其他保证或承诺。