Yoa*_*ein 3 c++ multithreading memory-model memory-barriers stdatomic
我一直在阅读Jeff Preshing 的这篇关于 Synchronizes-With Relation 的文章,以及cpp 参考中的std::memory_order页面中的“Release-Acquire Ordering”部分,但我不太明白:
似乎标准有某种承诺,但我不明白为什么有必要。让我们以 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();
}
Run Code Online (Sandbox Code Playgroud)
参考文献解释说:
如果线程 A 中的原子存储标记为 memory_order_release,并且线程 B 中来自同一变量的原子加载标记为 memory_order_acquire,则从线程的角度来看,在原子存储之前发生的所有内存写入(非原子和宽松原子) A,在线程 B 中成为可见的副作用。也就是说,一旦原子加载完成,线程 B 就保证可以看到线程 A 写入内存的所有内容。仅当 B 实际上返回 A 存储的值或释放序列中稍后的值时,此承诺才成立。
据我了解,当我们
ptr.store(p, std::memory_order_release)
Run Code Online (Sandbox Code Playgroud)
我们实际上正在做的是告诉编译器和CPU,运行时,使其无法在新值对线程t2可见后可见,data并且指向的内存将不再可见。std::string* pptr
同样,当我们
ptr.load(std::memory_order_acquire)
Run Code Online (Sandbox Code Playgroud)
我们告诉编译器和CPU:使其加载ptr不晚于*p2 和的加载data。
所以我不明白我们还有什么进一步的承诺?
这ptr.store(p, std::memory_order_release)(L1) 保证了在该特定线程 (T1) 中的该行之前完成的任何操作都将对其他线程可见,只要其他线程ptr以正确的方式读取(在本例中为使用std::memory_order_acquire)。此保证仅适用于这一对,仅此行不保证任何内容。
现在,另一个线程(T2)上有ptr.load(std::memory_order_acquire)(L2),它与另一个线程中的一对一起工作,保证只要它读取 T1 中写入的值,您就可以看到该行之前写入的其他值(在您的情况下)是data)。因为 L1与L2同步,data = 42; 所以发生在 之前 assert(data == 42)。
还有一个保证是ptr原子写入和读取,因为它是原子的。该代码中没有其他保证或承诺。
| 归档时间: |
|
| 查看次数: |
723 次 |
| 最近记录: |