2016-12-27 89 views
3

如果使用單個原子變量和std::memory_order_seq_cst,是否保證非原子操作不被重新排序?memory_order_seq_cst如何與非原子操作同步?

舉例來說,如果我有

std::atomic<bool> quux = {false}; 

void foo() { 
    bar(); 
    quux.store(true, std::memory_order_seq_cst); 
    moo(); 
} 

bar()不能保證的store通話後得到重新排序,並moo()不是的store調用之前,因爲我用std::memory_order_seq_cst得到重新排序,只要在至少從另一個線程的角度來看?

或者,把它放在代碼中,如果從另一個線程運行,下面的假設是有效的嗎?

if(quux.load(std::memory_order_seq_cst) == true) { 
    // bar guaranteed to be called; its side-effects are visible 
    // moo might have been called, but is not guaranteed to 
} else { 
    // bar might have been called, but is not guaranteed to 
    // moo might have been called, but is not guaranteed to 
} 

注意,我認爲,無論是bar也不moo使用原子操作,互斥鎖,柵欄或者其他同步功能。

回答

3

如果一個使用單個原子變量和std::memory_order_seq_cst,保證不會非原子操作來重新排序?

該標準是對這種http://en.cppreference.com/w/cpp/atomic/memory_order很清楚:

memory_order_seq_cst與此存儲器順序的任何操作是二者的獲取操作和釋放操作,加上單個總訂單存在其中所有線程遵守同一順序中的所有修改

memory_order_acquire使用此內存順序執行裝載操作會在受影響的內存位置執行獲取操作:no rea當前線程中的ds或寫入可以在此加載之前重新排序

memory_order_release與此存儲器順序的存儲操作執行釋放操作:沒有讀取或在當前線程寫入可以在此存儲之後被重新排序。

換句話說,可以在memory_order_seq_cst操作周圍沒有加載或存儲(包括非原子和原子)。


bar()不能保證店裏的電話後得到重新排序,並moo()不要讓商店的調用之前重新排序,只要我使用std :: memory_order_seq_cst,至少從的角度另一個線程?

如果barmoo的定義不是在當前轉換單元可用時,編譯器假定這些功能做存儲器加載和/或有副作用(做I/O或存儲到存儲器中),並且因此不能在memory_order_seq_cst左右的操作中重新排序。

如果定義可用並且函數不執行I/O或內存加載/存儲,則可以對它們進行重新排序。這些將是pure functions或功能,什麼也不做,並返回void或常數。

+0

Nitpicking,但是:雖然cppreference.com是一流的,但它不是ISO標準。 – Zeta

+0

@澤塔你是對的。我發現cppreference.com相當準確,但可能會有遺漏,因爲它不是標準的副本。 –

-2

由於使用了最嚴格的內存順序,所以函數bar和moo不能在存儲之前或之前分別重新排序。

您對if-else情況的結論不完全正確。

如果表達式if(quux.load(std::memory_order_seq_cst) == true)的計算結果爲true,那麼功能欄肯定已經完成了它的調用。呼叫moo的順序無法確定。它可能已經完成,沒有開始,或者可能在通話中。

如果提到的表達式評估爲false,那麼我們無法確定這兩個函數的順序。儘管在表達式計算結果爲false時,函數moo還沒有被調用,在執行else語句之前可能會調用moo函數。一旦在else子句中,函數moo的狀態與前一段中的相同(無法確定)。

0

根據@Maxim鏈接的鏈接http://en.cppreference.com/w/cpp/atomic/memory_order,關於memory_order_seq_cst存在錯誤。上面的文本與memory_order_acq_rel交換。 memory_order_seq_cst的文本:

memory_order_seq_cst:使用此存儲器順序的加載操作執行獲取操作,存儲執行釋放操作,並且讀取 - 修改 - 寫入執行獲取操作和釋放操作,再加上單個總數訂單存在於所有線程遵守同一訂單中的所有修改(請參見下面的順序一致排序)

因此,在您的情況下,存儲操作相當於一個釋放,這意味着moo()可以在fence之前重新排序。