2017-09-13 50 views
2

我想了解C++ 11的Relaxed Memory Ordering。我的理解是:在C++中輕鬆的內存排序

This ordering guarantees that the ordering of operations on a 
particular atomic variable doesn't change but ordering 
of operations of different atomic variables can change. The ordering here is 
within the same thread. For example, 

Thread 1 
operation A on atomic X 
operation B on atomic Y 
operation C on atomic Y 
operation D on atomic X 

Relaxed ordering guarantees that operation A will always happen-before 
operation D and operation B will always happen-before operation C. 
Having said that, the ordering of operations between X & Y can still change. 
That is, suppose the original code was like above. One possible execution 
order could be: 
operation A on atomic X 
operation D on atomic X 
operation B on atomic Y 
operation C on atomic Y 

如果我的理解錯誤,請糾正我。

我在下面寫了一個示例代碼來測試Relaxed Memory Ordering和預計assert有時會失敗。但它永遠不會失敗。我建Visual Studio 2017這一計劃,並與Intel(R) Core(TM) i7-6600U [email protected] 2.60GHz 2.80GHz

class RelaxedMemoryOrdering{ 
#define ARRAY_SIZE 4096 
public: 
    static int var_array[ARRAY_SIZE]; 
    RelaxedMemoryOrdering() { 
    for (int index = 0; index < ARRAY_SIZE; ++index) { 
     var_array[index] = 0; 
    } 
    sync1 = 0; 
    sync2 = 0; 
    sync3 = 0; 
    sync4 = 0; 
    sync5 = 0; 
    } 

    void thread1() { 
    sync1.store(1, std::memory_order_relaxed); 
    sync2.store(1, std::memory_order_relaxed); 
    sync3.store(1, std::memory_order_relaxed); 

    for (int index = 0; index < ARRAY_SIZE; ++index) { 
     var_array[index] = index + 1; 
    } 

    sync4.store(1, std::memory_order_relaxed); 
    sync5.store(1, std::memory_order_relaxed); 
    } 

    void thread2() { 
    while (!sync5.load(std::memory_order_relaxed)) { 
     ; 
    } 

    assert(sync4.load(std::memory_order_relaxed) == 1); 

    for (int index = 0; index < ARRAY_SIZE; ++index) { 
     assert(RelaxedMemoryOrdering::var_array[index] == (index + 1)); 
    } 

    assert(sync3.load(std::memory_order_relaxed) == 1); 
    assert(sync2.load(std::memory_order_relaxed) == 1); 
    assert(sync1.load(std::memory_order_relaxed) == 1); 
    } 

    void Test() { 
    std::thread t1(&RelaxedMemoryOrdering::thread1, this); 
    std::thread t2(&RelaxedMemoryOrdering::thread2, this); 
    t1.join(); 
    t2.join(); 
    } 

private: 
    std::atomic_int sync1{0}; 
    std::atomic_int sync2{0}; 
    std::atomic_int sync3{0}; 
    std::atomic_int sync4{0}; 
    std::atomic_int sync5{0}; 
}; 

static void TestRelaxedMemoryOrdering() { 
    while (1) { 
    { 
     RelaxedMemoryOrdering rmo; 
     rmo.Test(); 
    } 
    std::this_thread::sleep_for(std::chrono::milliseconds(10)); 
    }//while loop 
} 


int main() 
{ 
    TestRelaxedMemoryOrdering(); 
} 
+0

可能失敗的例子沒有圍欄:https://bartoszmilewski.com/2008/11/05/who-ordered-memory-fences-on-an-x86/ –

回答

3

在Intel x86架構的處理器上Windows 10運行時,MOV指令自動擁有獲得釋放語義,所以它可能無法觀察到的重新排序,你會從寬鬆預期語義。但是,您不應該依賴於此,因爲編譯器仍然可以對指令進行重新排序以達到優化目的。

https://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html

+0

很抱歉,但你能不能請將鏈接中的文字指向它。我沒有看到MOV說隱含在獲取釋放語義中的結果。 – Monku

+0

@Monku「Load Acquire:\t MOV(from memory)」「Store Release:\t MOV(進入內存)」 – Brian

+0

是的,但我上面的加載和存儲都是使用寬鬆排序的「顯式」。 – Monku

相關問題