一.如果只是簡單地解決在多線程中對共享資源的讀寫並發問題,只需要用C++以下內容: 線程類 thread, 原子數據類模板 atomic<T> t, 互斥 mutex, 鎖 lock, 條件變量 condition_variables.
二.在此基礎上,如果想在並行編程中獲得更好的性能,尤其當使用的是一些弱內存順序的平台(比如PowerPC)的話,設定原子操作間的內存順序則很有必要.
C++11 加入了支持並行編程的原子操作模塊,而所有的原子操作都有一個參數 memory_order.
1.內存模型 簡介
內存模型是一個硬件上的概念,表示機器指令是以什么樣的順序被處理器執行的 (現代的處理器不是逐條處理機器指令的) .
#include <thread> #include <atomic> atomic<int> a; atomic<int> b; void threadHandle() { int t = 1; a = t; b = 2; // b 的賦值不依賴 a }
在上面的線程處理函數中的三行代碼,在寄存器中實際執行順序可能與代碼寫的順序不一致.在不同的機器平台下,處理器有可能對指令周期的執行順序優化(一個時鍾周期發射多條指令),就是說它可能讓 b 的賦值語句比 a 的賦值語句先執行.
此時,如果有一個線程在循環地打印 a 和 b 的值,那么結果並不總是 a == 1 和 b == 2.
2.如何保證指令執行順序
保證執行順序會犧牲一些執行效率,因為這意味着放棄了編譯器、處理器等的優化處理。
強順序的內存模型指: 代碼順序和寄存器實際執行的順序一致
弱順序的內存模型指: 寄存器實際執行的順序與代碼順序不一致,被處理器調整過

3.C++ 並行編程: 設定 指令執行順序
typedef enum memory_order { memory_order_relaxed, // 不對執行順序做保證 memory_order_acquire, // 本線程中,所有后續的讀操作必須在本條原子操作完成后執行 memory_order_release, // 本線程中,所有之前的寫操作完成后才能執行本條原子操作 memory_order_acq_rel, // 同時包含 memory_order_acquire 和 memory_order_release memory_order_consume, // 本線程中,所有后續的有關本原子類型的操作,必須在本條原子操作完成之后執行 memory_order_seq_cst // 全部存取都按順序執行 } memory_order;
測試: 下面的代碼可能會打印出 a == 0; b == 2 這樣的結果
1 #include <iostream> 2 #include <thread> 3 #include <atomic> 4 5 atomic<int> a{ 0 }; 6 atomic<int> b{ 0 }; 7 void SetValue() 8 {// atomic類模板中的函數都是原子操作. int temp = a.load();相當於 int temp = a的原子操作 9 int t = 1; 10 a.store(t, memory_order_relaxed); // 相當於 a = t的原子操作 11 b.store(2, memory_order_relaxed); // 相當於 b = 2的原子操作 12 } 13 void Observer() 14 { 15 cout << a << b << endl; 16 } 17 18 int main() 19 { 20 thread T1(SetValue,0); 21 thread T2(Observer, 0); 22 23 T1.join(); // 主線程(調用方)等待子線程 T1 執行完成,才能繼續執行,阻塞 24 T2.join(); // 同上,執行這一行前: T1已經結束,T2很可能也結束了 25 26 return 0; 27 }
參考:C++ 多線程與內存模型資料匯
memory order相關問題
