2017-02-23 44 views
4

在下面的代碼中,由於原子線程限制,線程2中的x的值將始終爲10。從C++中的另一個線程讀取指針

int x; 
atomic<bool> b(false); 

// thread 1: 
x = 10; 
atomic_thread_fence(memory_order_release); 
b = true; 

// thread 2: 
while(!b){} 
atomic_thread_fence(memory_order_acquire); 
assert(x == 10); // x will always be 10 

但是在下面的代碼中,*x會在線程2中始終爲10嗎?

int* x = new int; 
atomic<bool> b(false); 

// thread 1: 
*x = 10; 
atomic_thread_fence(memory_order_release); 
b = true; 

// thread 2: 
while(!b){} 
atomic_thread_fence(memory_order_acquire); 
assert(*x == 10); // will *x always be 10? 
+1

我幾乎沒有看到任何區別。我認爲內存柵欄因爲原子布爾訪問而不需要。 – knivil

回答

8

在這兩種情況下,你得到10,這裏沒有區別存儲是否直接或通過一個指針來完成。

因爲b = true本質上是b.store(true, std::memory_order_seq_cst) - 帶籬笆的獲取 - 釋放,您不需要這裏的內存圍欄。

這樣的內存順序可以防止編譯器對操作進行重新排序存儲和加載,並在該存儲變得可見時使前面的存儲對其他線程可見。

如果你比較這兩個函數生成的代碼:

#include <atomic> 

int x; 
std::atomic<bool> b(false); 

void f() { 
    x = 10; 
    std::atomic_thread_fence(std::memory_order_release); 
    b = true; 
} 

void g() { 
    x = 10; 
    b = true; 
} 

是相同的:

f(): 
     movl $10, x(%rip) 
     movb $1, b(%rip) 
     mfence 
     ret 
g(): 
     movl $10, x(%rip) 
     movb $1, b(%rip) 
     mfence 
     ret 

在雖然你的具體情況,在我看來,你不需要超過std::memory_order_release存儲到b使店面x也可見其他線程,柵欄是不必要的。即b.store(true, std::memory_order_release)就夠了。消費者代碼需要做b.load(std::memory_order_acquire)

標準互斥鎖在獲取鎖定時獲取內存順序並在解鎖時釋放內存順序(這是術語獲取/釋放的來源),因此沒有涉及到柵欄。

這是非常罕見的一個明確的圍欄是必需的,主要是在硬件驅動程序。在用戶空間模式下,由於對C++ 11內存模型的誤解,通常會放置代碼。柵欄是最昂貴的原子同步機制,這是他們被避免的主要原因。

+0

評論不適用於擴展討論;這個談話已經[轉移到聊天](http://chat.stackoverflow.com/rooms/136680/discussion-on-answer-by-maxim-egorushkin-reading-pointers-from-another-thread-in)。 –

相關問題