C++原子類型操作與內存序

C++原子類型操作與內存序詳解

這段內容深入介紹了C++標準原子類型的操作接口、內存序語義及使用規范。以下是關鍵知識點的分層解析:

一、原子類型的命名規則與類型映射

C++提供兩種方式表示原子類型:

  1. 模板特化形式std::atomic<T>
  2. 別名形式atomic_前綴 + 類型名(內置類型有縮寫規則)

類型映射表

基礎類型原子類型(模板特化)原子類型(別名)
intstd::atomic<int>atomic_int
unsignedstd::atomic<unsigned>atomic_uint
long longstd::atomic<long long>atomic_llong
void*std::atomic<void*>atomic_pointer

最佳實踐:優先使用std::atomic<T>,避免因編譯器差異導致的兼容性問題。

二、原子類型的操作限制與接口設計

1. 禁用拷貝語義

原子類型不支持拷貝構造和拷貝賦值,防止數據競爭:

std::atomic<int> a(42);
// std::atomic<int> b(a);  // 錯誤:拷貝構造被刪除
// b = a;                  // 錯誤:拷貝賦值被刪除
2. 核心操作分類
  • 存儲操作store()、賦值運算符(=
  • 加載操作load()、隱式類型轉換
  • 讀-改-寫操作(RMW)fetch_add()exchange()compare_exchange_weak/strong()
3. 操作返回值設計
  • 賦值運算符返回存儲的值
  • 命名函數(如fetch_add())返回操作前的值

示例對比

std::atomic<int> x(10);
int a = x.fetch_add(5);  // a = 10(操作前的值),x = 15
int b = (x += 5);        // b = 20(存儲的值),x = 20

三、用戶自定義類型的原子支持

std::atomic主模板可用于用戶自定義類型,但需滿足:

  1. 類型必須是Trivially Copyable(即有平凡拷貝構造/賦值、析構函數)
  2. 操作僅限于:load()store()exchange()compare_exchange_*

示例

struct Point {int x, y;
};  // 滿足Trivially Copyablestd::atomic<Point> atomic_point;
Point p = {1, 2};
atomic_point.store(p);

四、內存序的分類與適用場景

內存序控制原子操作的同步強度,影響編譯器和CPU的指令重排:

1. 六大內存序值
內存序適用操作同步強度典型場景
memory_order_relaxed所有操作最弱(僅保證原子性)計數器自增(無需同步順序)
memory_order_release存儲操作釋放語義發布數據(配合acquire使用)
memory_order_acquire加載操作獲取語義獲取由release發布的數據
memory_order_consume加載操作弱獲取(已棄用)基于依賴關系的同步
memory_order_acq_relRMW操作同時具備acquire/release實現鎖(如compare_exchange)
memory_order_seq_cst所有操作最強(全序)默認值,簡化同步推理
2. 內存序組合示例
std::atomic<bool> ready(false);
std::atomic<int> data(0);// 線程1:發布數據
data.store(42, std::memory_order_relaxed);
ready.store(true, std::memory_order_release);  // 釋放屏障// 線程2:獲取數據
while (!ready.load(std::memory_order_acquire));  // 獲取屏障
int value = data.load(std::memory_order_relaxed);  // 保證讀到42

五、原子操作的默認行為

若未顯式指定內存序,原子操作默認使用memory_order_seq_cst(順序一致性):

  • 所有線程觀察到的操作順序完全一致
  • 相當于所有操作都有全序關系
  • 性能開銷最高,但簡化了同步推理

示例

std::atomic<int> x(0), y(0);// 線程1
x.store(1);  // 默認memory_order_seq_cst// 線程2
y.store(1);  // 默認memory_order_seq_cst// 線程3
while (x.load() == 0);
if (y.load() == 0) { /* 此處永遠不會執行 */ }

六、性能優化建議

  1. 避免過度同步

    • 對無順序要求的操作(如計數器)使用memory_order_relaxed
    • 示例:
      std::atomic<int> counter(0);
      counter.fetch_add(1, std::memory_order_relaxed);  // 僅保證原子性
      
  2. 使用release/acquire對

    • 在生產者-消費者模型中,生產者使用release,消費者使用acquire
    • 示例:
      // 生產者線程
      buffer = prepare_data();
      ready.store(true, std::memory_order_release);// 消費者線程
      while (!ready.load(std::memory_order_acquire));
      process(buffer);
      
  3. 謹慎使用seq_cst

    • 僅在需要全局順序保證時使用
    • 多數場景可通過release/acquire實現相同邏輯,性能更優

七、總結:原子操作的核心價值

  1. 提供輕量級同步:通過硬件指令避免鎖的開銷
  2. 精確控制內存序:在性能和正確性間取得平衡
  3. 支持用戶自定義類型:擴展原子操作的應用范圍

理解原子操作的接口設計和內存序語義,是編寫高性能并發代碼的關鍵。在實際應用中,應優先使用std::atomic模板特化,并根據場景選擇合適的內存序,避免不必要的同步開銷。

C++原子類型操作全解析:分類、實例與應用場景

C++原子類型提供了豐富的操作接口,按功能可分為基礎操作、算術操作、位操作和CAS操作四大類。不同操作適用于不同的并發場景,合理選擇能顯著提升程序性能與安全性。

一、基礎操作:加載、存儲與交換

1. 核心接口
操作類型函數名稱運算符重載說明
存儲(Store)store(T value)atomic_var = value原子寫入值,可選內存序
加載(Load)load()(T)atomic_var原子讀取值,可選內存序
交換(Exchange)exchange(T desired)原子替換值并返回舊值,可選內存序
2. 典型應用場景
  • 線程間標志傳遞:使用store/release發布數據,load/acquire獲取數據
    std::atomic<bool> ready(false);// 生產者線程
    void producer() {data = prepare();ready.store(true, std::memory_order_release);
    }// 消費者線程
    void consumer() {while (!ready.load(std::memory_order_acquire));process(data);
    }
    
  • 實現無鎖單例模式:使用exchange原子初始化指針
    std::atomic<Singleton*> instance(nullptr);Singleton* getInstance() {Singleton* tmp = instance.load();if (!tmp) {tmp = new Singleton();if (!instance.exchange(tmp)) {delete tmp;tmp = instance.load();}}return tmp;
    }
    

二、算術操作:原子增減與復合賦值

1. 核心接口
操作類型函數名稱運算符重載說明
加法fetch_add(T value)+=原子加并返回舊值,適用于整數/指針
減法fetch_sub(T value)-=原子減并返回舊值,適用于整數/指針
前置/后置自增++atomic_varatomic_var++原子自增,返回新值/舊值
前置/后置自減--atomic_varatomic_var--原子自減,返回新值/舊值
2. 典型應用場景
  • 高性能計數器:使用fetch_add實現無鎖計數
    std::atomic<int> counter(0);void worker() {for (int i = 0; i < 1000; ++i) {counter.fetch_add(1, std::memory_order_relaxed);}
    }
    
  • 資源引用計數:使用fetch_sub實現原子釋放資源
    struct Resource {std::atomic<int> ref_count{1};void add_ref() { ref_count.fetch_add(1); }void release() {if (ref_count.fetch_sub(1) == 1) {delete this;}}
    };
    

三、位操作:原子按位運算

1. 核心接口
操作類型函數名稱運算符重載說明
按位或fetch_or(T value)`=`
按位與fetch_and(T value)&=原子按位與并返回舊值
按位異或fetch_xor(T value)^=原子按位異或并返回舊值
2. 典型應用場景
  • 標志位管理:使用fetch_orfetch_and原子設置/清除標志
    enum Flags {INITIALIZED = 1 << 0,CONNECTED = 1 << 1,READY = 1 << 2
    };std::atomic<int> status(0);// 設置INITIALIZED標志
    status.fetch_or(INITIALIZED, std::memory_order_relaxed);// 清除CONNECTED標志
    status.fetch_and(~CONNECTED, std::memory_order_relaxed);
    
  • 并發位圖(BitSet):使用原子位操作實現線程安全位圖
    class AtomicBitSet {std::atomic<uint64_t> bits{0};public:bool test_and_set(size_t pos) {uint64_t mask = 1ULL << pos;return bits.fetch_or(mask) & mask;}
    };
    

四、CAS操作:比較并交換

1. 核心接口
函數名稱說明
compare_exchange_weak(T& expected, T desired)弱CAS,可能因硬件原因失敗,需循環重試
compare_exchange_strong(T& expected, T desired)強CAS,保證一次成功或失敗
2. 典型應用場景
  • 實現無鎖棧:使用CAS原子更新棧頂指針
    template<typename T>
    class LockFreeStack {struct Node { T data; Node* next; };std::atomic<Node*> head{nullptr};public:void push(const T& value) {Node* new_node = new Node{value, head.load()};while (!head.compare_exchange_weak(new_node->next, new_node));}
    };
    
  • 原子累加器:使用CAS實現更高效的累加(比fetch_add減少緩存爭用)
    class AtomicAccumulator {std::atomic<int> value{0};public:void add(int delta) {int expected = value.load();while (!value.compare_exchange_weak(expected, expected + delta));}
    };
    

五、操作選擇決策樹

是否需要原子讀寫?
│
├── 是 → 是否只需存儲/加載?
│   │
│   ├── 是 → 使用 store()/load() 或賦值/類型轉換
│   │
│   ├── 否 → 是否需要原子替換值?
│       │
│       ├── 是 → 使用 exchange()
│       │
│       ├── 否 → 是否需要原子比較并替換?
│           │
│           ├── 是 → 使用 compare_exchange_weak/strong()
│           │
│           ├── 否 → 是否為整數或指針類型?
│               │
│               ├── 是 → 是否需要算術操作?
│               │   │
│               │   ├── 是 → 使用 fetch_add()/fetch_sub() 或 +=/-=
│               │   │
│               │   ├── 否 → 是否需要位操作?
│               │       │
│               │       ├── 是 → 使用 fetch_or()/fetch_and() 等
│               │       │
│               │       └── 否 → 無匹配操作
│               │
│               └── 否 → 無匹配操作(僅支持基本原子操作)
│
└── 否 → 使用普通變量

六、性能優化建議

  1. 優先使用無鎖操作

    • 對簡單計數使用fetch_add替代互斥鎖
    • 示例:counter.fetch_add(1, std::memory_order_relaxed)
  2. 合理選擇CAS類型

    • 循環次數較多時使用compare_exchange_strong
    • 性能敏感場景使用compare_exchange_weak并循環重試
  3. 內存序優化

    • 無順序要求的操作使用memory_order_relaxed
    • 發布-訂閱模型使用memory_order_release/acquire
  4. 避免偽共享(False Sharing)

    • 使用alignas確保原子變量對齊到緩存行
    struct alignas(64) Counters {std::atomic<int> counter1{0};std::atomic<int> counter2{0};  // 與counter1分開在不同緩存行
    };
    

七、總結:操作與場景映射表

操作類型核心函數典型應用場景
存儲/加載store(), load()線程間標志傳遞、狀態同步
交換exchange()單例模式初始化、資源所有權轉移
算術操作fetch_add(), ++計數器、引用計數、負載均衡
位操作fetch_or(), &=并發位圖、標志位管理、狀態機實現
CAS操作compare_exchange_*無鎖數據結構(棧、隊列)、原子累加器、復雜狀態更新

理解原子操作的分類和適用場景,是編寫高性能并發代碼的關鍵。在實際應用中,應根據操作的原子性需求、性能要求和同步語義,選擇最合適的原子操作類型和內存序。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/87842.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/87842.shtml
英文地址,請注明出處:http://en.pswp.cn/web/87842.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

互聯網摸魚日報(2025-07-07)

互聯網摸魚日報(2025-07-07) 鈦媒體 一場突如其來的“召回潮”&#xff0c;點燃中國制造的“靈魂拷問” 史上最大外賣補貼戰開打&#xff0c;美團聚攏資源迎戰“巨無霸” 1315億加冕潮汕女首富&#xff0c;“最強打工妹”劍指港股 用14346字&#xff0c;講透上市前必做的10…

七牛云Java開發面試題及參考答案

詳述 Java 方法重載的機制與應用場景 Java 方法重載&#xff08;Method Overloading&#xff09;是面向對象編程中的重要特性&#xff0c;它允許同一個類中存在多個同名但參數列表不同的方法。這種機制為代碼提供了靈活性和可讀性&#xff0c;使得開發者可以用統一的方法名處理…

.net core mvc部署到win10本地的Ubuntu上

將一個 .NET Core MVC 應用部署到 Windows 10 上通過 WSL 安裝的 Ubuntu 環境中&#xff0c;可以分為幾個步驟來完成。以下是詳細的指南&#xff1a;準備工作確保你的Ubuntu環境已安裝.NET SDK&#xff1a;首先&#xff0c;你需要在WSL中的Ubuntu上安裝.NET SDK。可以通過以下命…

機器人VLA模型(Vision-Language-Action)

一、VLA模型的技術架構與核心原理 VLA&#xff08;Vision-Language-Action&#xff09;模型的核心是構建視覺、語言、動作的多模態閉環系統&#xff0c;實現從感知到執行的端到端映射。其技術架構可細分為四個關鍵模塊&#xff1a; 1. 多模態編碼器 視覺編碼器&#xff1a; …

單點登錄SSO的演進和最佳實踐,含springBoot 實現(Java版本)

一、單點登錄&#xff08;SSO&#xff09;概述 單點登錄&#xff08;SSO, Single Sign-On&#xff09;是一種認證機制&#xff0c;允許用戶只需登錄一次&#xff0c;即可訪問多個相互信任的系統或應用&#xff0c;而不需要為每個系統重復登錄。 二、SSO 演進路徑 我們可以從以…

Python----OpenCV(圖像増強——高通濾波(索貝爾算子、沙爾算子、拉普拉斯算子),圖像浮雕與特效處理)

一、 高通濾波 高通濾波是對圖像進行卷積操作&#xff0c;以保留圖像中的快速變化部分&#xff08;如邊緣和細節&#xff09;&#xff0c;同時抑 制低頻分量&#xff08;如大面積平坦區域&#xff09;。 應用場景 邊緣檢測&#xff1a;提取物體輪廓和邊界。特征提取&#xff…

oracle 恢復

RECOVER DATABASE USING BACKUP CONTROLFILE “用備份的控制文件推動數據庫恢復”。-- 檢查控制文件記錄的當前SCN (V$DATABASE) SELECT CURRENT_SCN FROM V$DATABASE; -- 檢查數據文件頭SCN (V$DATAFILE_HEADER) SELECT FILE#, CHECKPOINT_CHANGE# FROM V$DATAFILE_HEADER;-…

京東商品詳情SKU數據采集的難點有哪些?

京東商品詳情 SKU 數據采集過程中&#xff0c;由于平臺的技術防護、數據結構特性及合規性要求&#xff0c;會面臨諸多難點&#xff0c;具體如下&#xff1a;一、反爬蟲機制的限制京東作為大型電商平臺&#xff0c;擁有成熟且嚴格的反爬蟲系統&#xff0c;這是采集時最核心的障礙…

修復手機液晶面板顯性橫向線性不良定位及相關液晶線路激光修復原理

摘要 手機液晶面板顯性橫向線性不良嚴重影響屏幕顯示效果&#xff0c;其產生與液晶線路斷路、短路或信號傳輸異常密切相關。精準定位線性不良區域是修復的關鍵前提&#xff0c;激光修復技術憑借高能量密度與非接觸特性&#xff0c;能夠有效修復相關液晶線路故障。本文分析顯性…

如何解決Spring Boot中@Valid對List校驗失效問題

在Spring Boot應用開發中&#xff0c;我們經常需要對傳入的請求參數進行校驗&#xff0c;以確保數據的合法性和安全性。然而&#xff0c;當我們嘗試對列表&#xff08;List&#xff09;類型的參數進行校驗時&#xff0c;可能會遇到校驗失效的問題。本文將詳細探討這一問題的失效…

云原生環境下部署大語言模型服務:以 DeepSeek 為例的實戰教程

&#x1f4dd;個人主頁&#x1f339;&#xff1a;一ge科研小菜雞-CSDN博客 &#x1f339;&#x1f339;期待您的關注 &#x1f339;&#x1f339; 一、引言 隨著 DeepSeek、Qwen、ChatGLM 等大語言模型&#xff08;LLM&#xff09;的開放與普及&#xff0c;企業將其私有化部署…

【Spring篇08】:理解自動裝配,從spring.factories到.imports剖析

文章目錄1. 自動化裝配的起點&#xff1a;SpringBootApplication2. 自動化裝配的核心機制&#xff1a;EnableAutoConfiguration 和 AutoConfigurationImportSelector3. 自動化配置的注冊方式&#xff1a;spring.factories 與 .imports3.1 早期版本&#xff1a;META-INF/spring.…

前置代理重構網絡訪問的「中轉站」

某跨境電商通過前置代理構建賬號隔離體系&#xff0c;將亞馬遜店鋪關聯風險降低85%&#xff1b;某企業利用前置代理過濾惡意流量&#xff0c;網絡攻擊攔截率提升70%。在復雜的網絡環境中&#xff0c;前置代理作為客戶端與目標服務器之間的「中間樞紐」&#xff0c;正成為跨境訪…

樂鑫代理商飛睿科技,2025年AI智能語音助手市場發展趨勢與樂鑫芯片解決方案分析

一、市場現狀與技術背景進入2025年&#xff0c;AI智能語音助手市場呈現出爆發性增長態勢。全球AI應用訪問量從2024年初的36億次激增至76億次&#xff0c;增幅高達111%&#xff0c;其中語音交互類產品貢獻了顯著份額。在企業市場&#xff0c;語音技術已從“增值服務”轉變為不可…

App爬蟲工具篇-Appium安裝

之前在另外一篇文章App爬蟲工具篇-mitmproxy簡單介紹了利用mitmproxy進行接口攔截來獲取接口數據。但是很多軟件現在都會對相關接口進行加密。如以下我用mitmproxy攔截到接口流量樣例: {"raw_data": "EXMcAezXPq/MRC1m2mJIG/EQLisaahfpjPTj9svrxe6yLI8mZTvW4+…

容器與 Kubernetes 基本概念與架構

文章目錄 1. 典型環境層次結構2. Kubernetes 生態三大類2.1 核心組件2.2 集群管理工具2.3 生態輔助工具2.4 資源管理關系 3. Docker 容器技術與實踐3.1 鏡像拉取加速3.2 認證與登錄3.3 常用命令3.4 存儲掛載方式對比3.5 docker-compose 啟動3.6 容器化應用部署示例 4. kind 快速…

Ajax和Axios的初步學習

Ajax 一、什么是 Ajax&#xff1f; Ajax (Asynchronous JavaScript and XML) 是一種無需重新加載整個網頁的情況下&#xff0c;能夠更新部分網頁的技術。通過在后臺與服務器進行少量數據交換&#xff0c;Ajax 可以使網頁實現異步更新。 主要特性&#xff1a; 異步性 (Asynch…

C#指針:解鎖內存操作的底層密碼

C#指針&#xff1a;解鎖內存操作的底層密碼 在 C# 的世界里&#xff0c;我們習慣了托管代碼帶來的安全與便捷 —— 垃圾回收器自動管理內存&#xff0c;類型系統嚴格檢查數據操作&#xff0c;就像在精心維護的花園中漫步&#xff0c;無需擔心雜草與荊棘。但當性能成為關鍵瓶頸…

永洪科技榮獲商業智能品牌影響力獎,全力打造”AI+決策”引擎

近日&#xff0c;在備受業界矚目的年度商業智能領域權威評選中&#xff0c;永洪科技憑借卓越的技術實力、深度的客戶價值創造能力與前瞻的行業洞察&#xff0c;成功斬獲“2025商業智能品牌影響力獎”。這一獎項不僅是對永洪科技市場地位與品牌聲量的高度認可&#xff0c;更是對…

在SSM+vue項目中上傳表單數據和文件

從前端向后端發送multipart/form-data 類型數據&#xff08;主要用于文件上傳或表單提交&#xff09;如發送如下信息&#xff1a;前端代碼vue文件&#xff1a;&#xff08;配置了服務器代理&#xff09;<template><div class"content"><el-form :mode…