我一直在閱讀Jeff Preshing 關于同步關系的這篇文章,以及 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();
}
該參考資料解釋說:
如果執行緒 A 中的原子存盤標記為 memory_order_release,并且執行緒 B 中來自同一變數的原子加載標記為 memory_order_acquire,則從執行緒的角度來看,在原子存盤之前發生的所有記憶體寫入(非原子和寬松原子) A,在執行緒 B 中成為可見的副作用。也就是說,一旦原子加載完成,執行緒 B 保證可以看到執行緒 A 寫入記憶體的所有內容。僅當 B 實際上回傳 A 存盤的值或發布序列中稍后的值時,此承諾才成立。
據我了解,當我們
ptr.store(p, std::memory_order_release)
我們實際上正在做的是告訴編譯器和 CPU,在運行時,讓它沒有辦法,并且在執行緒 t2 可以看到新值之后,data指向的記憶體將是可見的。std::string* pptr
And same, when we
ptr.load(std::memory_order_acquire)
We are telling the compiler and CPU: make it so the loading of ptr will be no later than then loading of *p2 and data.
So I don't understand what further promise we have here?
uj5u.com熱心網友回復:
這ptr.store(p, std::memory_order_release)(L1) 保證在此特定執行緒 (T1) 中此行之前所做的任何事情都將對其他執行緒可見,只要這些其他執行緒ptr以正確的方式讀取(在這種情況下,使用std::memory_order_acquire)。此保證僅適用于這對,僅此行不保證任何內容。
現在您ptr.load(std::memory_order_acquire)在另一個執行緒 (T2) 上有 (L2),它與另一個執行緒的對一起作業,保證只要它讀取 T1 中寫入的值,您就可以看到在該行之前寫入的其他值(在您的情況下它是data)。所以因為 L1與L2同步,所以data = 42; 發生在 assert(data == 42).
還有一個保證ptr是原子地寫入和讀取的,因為它是原子的。該代碼中沒有其他保證或承諾。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/451969.html
標籤:c multithreading memory-barriers
下一篇:從不同執行緒訪問佇列兩端時的同步
