什么是"与同步"关系



我一直在读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可见之后,datastd::string* p指向的内存可见。

同样,当我们

ptr.load(std::memory_order_acquire)

我们告诉编译器和CPU:这样ptr的加载就不会晚于*p2data的加载。

所以我不明白我们还有什么进一步的承诺?

这个ptr.store(p, std::memory_order_release)(L1(保证,只要其他线程以正确的方式读取ptr(在本例中,使用std::memory_order_acquire(,在该特定线程(T1(中该行之前所做的任何事情都将对其他线程可见。此保证仅适用于此对,仅此线不保证任何内容。

现在,在另一个线程(T2(上有ptr.load(std::memory_order_acquire)(L2(,它与来自另一线程的对一起工作,保证只要它读取T1中写入的值,就可以看到在该行之前写入的其他值(在您的情况下,它是data(。因此,由于L1L2同步,data = 42;发生在assert(data == 42)之前。

此外,还可以保证ptr是以原子方式写入和读取的,因为它是原子的。该准则中没有其他保证或承诺。

最新更新