什么是C++中的內存序選項 六種memory_order應用場景對比

c++++內存序有六種,分別是memory_order_relaxed、memory_order_consume、memory_order_acquire、memory_order_release、memory_order_acq_rel、memory_order_seq_cst;它們分別用于控制原子操作的內存可見性和順序約束,其中relaxed僅保證原子性,consume用于數據依賴,acquire防止后續操作重排到加載前,release防止前面操作重排到存儲后,acq_rel結合兩者用于cas操作,seq_cst提供全局順序一致性;選型時根據場景選擇,統計用relaxed,同步配合使用acquire/release,cas優先acq_rel,默認用seq_cst,consume較少使用。

什么是C++中的內存序選項 六種memory_order應用場景對比

c++線程編程中,內存序(memory_order)是控制原子操作之間內存可見性和順序約束的關鍵機制。它不是簡單的“先后執行”的問題,而是影響編譯器和CPU如何重排指令、如何同步數據的問題。

什么是C++中的內存序選項 六種memory_order應用場景對比

如果你寫過多線程程序,尤其是涉及無鎖結構(如lock-free隊列、原子計數器等),就一定會遇到這個問題。不同memory_order選項影響性能和正確性,選錯可能導致數據競爭或過度加鎖,拖慢程序。

什么是C++中的內存序選項 六種memory_order應用場景對比


memory_order有哪些?基本分類

C++11標準定義了六種內存序選項,它們分別是:

立即學習C++免費學習筆記(深入)”;

  • memory_order_relaxed:最寬松,不提供順序保證
  • memory_order_consume:用于依賴鏈中的加載操作(實際應用較少)
  • memory_order_acquire:確保當前加載操作之后的讀寫不會被重排到該操作之前
  • memory_order_release:確保當前存儲操作之前的讀寫不會被重排到該操作之后
  • memory_order_acq_rel:結合 acquire 和 release,用于原子交換或CAS操作
  • memory_order_seq_cst:默認順序,完全順序一致性,代價最高但最容易理解

這些選項決定了兩個線程之間如何看到彼此的操作順序。

什么是C++中的內存序選項 六種memory_order應用場景對比


不同場景下怎么選?關鍵對比

1. 只需要保證原子性,不關心順序 —— memory_order_relaxed

這是最輕量級的選擇,適合只關注值的原子更新,不關心其他線程何時看到變化的情況。

比如一個簡單的計數器統計訪問次數:

std::atomic<int> count{0}; count.fetch_add(1, std::memory_order_relaxed);

注意點

  • 它不能用來同步其他變量
  • 如果你用它來實現同步邏輯,很可能引入數據競爭

2. 保護后續操作的數據依賴 —— memory_order_consume

這個選項限制了依賴于當前加載值的后續操作不能被提前。例如:

std::atomic<std::string*> ptr; std::string* p = ptr.load(std::memory_order_consume); if (p) {     std::cout << *p; // 依賴于ptr的值 }

適用范圍較窄,現代編譯器和硬件優化后,實際效果與acquire差別不大,使用頻率不高。

3. 控制加載后的可見性 —— memory_order_acquire

當你從一個共享變量讀取標志位,并希望確保后續代碼能看到其他線程在此之前寫入的數據時,就要用它。

比如線程B等待線程A設置完成某個標志:

// 線程A data = 42; ready.store(true, std::memory_order_release);  // 線程B while (!ready.load(std::memory_order_acquire)) ; assert(data == 42); // 能看到前面的寫入

重點

  • 配合release一起使用才能形成同步關系
  • 單獨使用acquire無法保證完整的順序一致性

4. 控制寫入前的順序 —— memory_order_release

這個選項確保當前寫入操作之前的所有讀寫都不會被重排到它后面。通常用于通知其他線程某個狀態已經準備好。

上面的例子中線程A用了release,就是為了防止data=42被重排到store之后。

常見用途

  • 設置條件變量標志
  • 發布初始化完成的指針

5. 原子操作既要acquire又要release —— memory_order_acq_rel

適用于像compare_exchange_strong這樣的原子操作,既要看又要改。

比如實現一個簡單的自旋鎖:

bool expected = false; while (!lock.compare_exchange_weak(expected, true, std::memory_order_acq_rel)) {     expected = false; }

說明

  • 它相當于“先獲取再釋放”
  • 用于修改狀態并影響其他線程的行為

6. 默認選擇,簡單粗暴 —— memory_order_seq_cst

這是默認的內存序,也是最安全的選項。所有線程看到的操作順序一致。

x.store(1); // 默認就是seq_cst y.store(2);

優點

  • 簡單直觀,不容易出錯
  • 在大多數情況下足夠快

缺點

  • 性能開銷最大,尤其是在多核系統上

實際建議總結

  • 如果只是統計、計數,用relaxed
  • 涉及線程間同步,成對使用acquire/release
  • CAS類操作優先考慮acq_rel
  • 一般情況下用seq_cst,除非你能明確需要更弱的順序
  • consume幾乎不用,了解即可

基本上就這些,別太追求極致性能,除非你真有性能瓶頸。

? 版權聲明
THE END
喜歡就支持一下吧
點贊6 分享