std::map 加鎖

在并發環境下使用std::map,必須采取同步措施。
在并發環境下對 std::map 進行不加鎖的讀寫操作會導致嚴重的線程安全問題,主要會產生以下幾種問題:

?? 主要風險與后果

  1. 數據競爭(Data Race)

    • 當多個線程同時修改同一個鍵值對時
    • 底層紅黑樹結構可能被破壞
    • 導致內存損壞、程序崩潰或不可預測行為
  2. 迭代器失效

    • 線程A遍歷map時,線程B插入/刪除元素
    • 迭代器可能失效(野指針)
    • 導致訪問越界或段錯誤(Segmentation Fault)
  3. 臟讀(Stale Read)

    • 線程A正在修改節點,線程B同時讀取
    • 可能讀取到部分更新的數據(半寫狀態)
    • 獲取到不一致或無效的數據
  4. 死循環/崩潰

    • 紅黑樹平衡操作被并發打斷
    • 樹結構被破壞導致無限循環
    • 常見于插入/刪除操作沖突時
  5. 性能下降

    • CPU緩存一致性協議(MESI)頻繁失效
    • 大量CPU時間浪費在緩存同步上
    • 實際性能可能比加鎖版本更差

🔍 具體問題場景分析

std::map<int, string> sharedMap;// 線程1
void writer() {for(int i=0; i<1000; ++i) {sharedMap[i] = to_string(i); // 并發寫}
}// 線程2
void reader() {for(auto& [k,v] : sharedMap) { // 并發讀cout << v << endl;}
}// 運行兩個線程 -> 崩潰風險極高

? 解決方案(并發安全訪問)

方案1:互斥鎖(最常用)
#include <mutex>
std::mutex mapMutex;// 安全寫入
void safeWrite(int k, string v) {std::lock_guard<std::mutex> lock(mapMutex);sharedMap[k] = v;
}// 安全讀取
string safeRead(int k) {std::lock_guard<std::mutex> lock(mapMutex);return sharedMap.at(k); // 使用at避免自動插入
}
方案2:讀寫鎖(C++17+ 讀多寫少場景)
#include <shared_mutex>
std::shared_mutex rwMutex;// 寫操作(獨占鎖)
void safeWrite(int k, string v) {std::unique_lock lock(rwMutex);sharedMap[k] = v;
}// 讀操作(共享鎖)
string safeRead(int k) {std::shared_lock lock(rwMutex); // 多個讀可并發return sharedMap.at(k);
}
方案3:線程安全容器(推薦)
#include <tbb/concurrent_hash_map.h>tbb::concurrent_hash_map<int, string> safeMap;// 寫操作
void safeWrite(int k, string v) {tbb::concurrent_hash_map<int, string>::accessor acc;safeMap.insert(acc, k);acc->second = v;
}// 讀操作
string safeRead(int k) {tbb::concurrent_hash_map<int, string>::const_accessor acc;if(safeMap.find(acc, k)) {return acc->second;}throw std::out_of_range("Key not found");
}
方案4:無鎖編程(高級技巧)
#include <atomic>
#include <memory>// 使用atomic智能指針實現COW
std::atomic<std::shared_ptr<std::map<int, string>>> atomicMap;void safeWrite(int k, string v) {auto newMap = std::make_shared<std::map<int, string>>(*atomicMap.load());(*newMap)[k] = v;atomicMap.store(newMap); // 原子切換
}// 讀操作(完全無鎖)
string safeRead(int k) {auto current = atomicMap.load(); // 原子讀取return current->at(k);
}

📊 性能對比(讀多寫少場景)

方案10讀/1寫100讀/1寫安全性
無保護崩潰崩潰?
互斥鎖中等?
讀寫鎖良好優秀?
concurrent_hash_map優秀極佳?
COW無鎖極佳極佳?

?? 重要注意事項

  1. 迭代器安全問題

    // 危險操作(即使加鎖)
    auto it = safeMap.begin();
    // 此處鎖已釋放,其他線程可能修改map
    // 后續使用it可能失效
    
  2. 復合操作問題

    // 非原子復合操作
    if(map.count(key)) {      // 檢查value = map.at(key);  // 獲取
    } // 兩個操作間map可能被修改
    
  3. C++17 提取節點優化

    std::lock_guard lock(mutex);
    if(auto node = map.extract(key)) {// 安全操作節點(map已移除該元素)modify_node(node);map.insert(std::move(node));
    }
    

💡 最佳實踐建議

  1. 優先使用標準庫方案

    • 讀寫鎖(C++17的std::shared_mutex
    • 對于新項目優先考慮tbb::concurrent_hash_map
  2. 避免長期持有鎖

    // 反例
    {std::lock_guard lock(mutex);auto data = map.at(key); // 獲取數據process(data); // 長時間處理(鎖被長期占用)
    }
    
  3. 使用范圍鎖優化

    std::map<int, Data> snapshot;
    {std::lock_guard lock(mutex);snapshot = map; // 快速拷貝
    }
    // 在無鎖狀態下處理snapshot
    
  4. 考慮并發有序容器替代方案

    • folly::AtomicHashMap(Facebook)
    • ska::flat_hash_map(高性能哈希)
    • libcds::MichaelHashMap(無鎖實現)

在并發環境下使用任何STL容器都必須考慮線程安全性。對于std::map,強烈建議始終使用適當的同步機制,避免未加鎖的并發訪問。

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

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

相關文章

學習筆記090——Ubuntu 中 UFW 防火墻的使用

文章目錄1、允許特定的端口訪問2、允許特定 IP 訪問某個端口3、允許某個范圍的端口4、查看 UFW 狀態5、重新加載 UFW6、啟用 UFW7、關閉 UFW1、允許特定的端口訪問 # 允許 TCP 端口&#xff08;例如 80&#xff09;&#xff1a; sudo ufw allow 80/tcp# 允許 UDP 端口&#xf…

移動端 WebView 內存泄漏與性能退化問題如何排查 實戰調試方法匯總

在混合 App 應用中&#xff0c;WebView 頁面常承載復雜業務邏輯與交互。隨著用戶使用時間增長&#xff0c;特別在切換多個頁面或反復打開界面后&#xff0c;常常會出現性能下降、頁面卡頓、甚至白屏崩潰等現象。這通常是因為頁面存在內存泄漏、事件監聽未解綁或垃圾回收阻塞導致…

JSON 對象在瀏覽器中順序與后端接口返回不一致的問題

一、問題描述 后端接口返回一個字典表的JSON對象&#xff0c;頁面展示排序與預期排序不一致。 在瀏覽器調試面板Response中看到接口原始響應字符串&#xff0c;是期望順序&#xff1a;在Preview中看到&#xff0c; key “22” 被提到最前&#xff0c;順序發生變化&#xff1a;頁…

Spring MVC數據傳遞全攻略

Spring MVC數據傳遞一、前端到后端的數據傳遞1. 使用 RequestParam 傳遞簡單參數2. 使用 PathVariable傳遞路徑參數3. 使用RequestBody傳遞 JSON 數據二、后端到前端的數據傳遞1. 使用Model或 ModelAndView傳遞數據到前端2. 使用HttpServletResponse直接寫回數據3.使用Response…

倉庫管理系統-12-前端之頭部區域Header基于嵌套路由訪問個人中心

文章目錄 1 個人中心 1.1 DateUtils.vue(子組件) 1.2 Home.vue(父組件) 1.3 router/index.js(嵌套路由) 1.4 index.vue(路由占位符) 2 Header.vue 2.1 頁面布局 2.2 toUser方法 2.3 初始加載 2.4 Header.vue 頭部區域Header中有一個個人中心下拉菜單,點擊個人中心選項,通過嵌…

【智能協同云圖庫】第七期:基于AI調用阿里云百煉大模型,實現AI圖片編輯功能

摘要&#xff1a;AI 高速發展賦能傳統業務&#xff0c;圖庫網站亦有諸多 AI 應用空間。以 AI 擴圖功?能為例&#xff0c;讓我們來學習如何在項目?中快速接入 AI 繪圖大模型。?用戶可以選擇一張已上傳的圖片&#xff0c;?通過 AI 擴圖得到新的圖片&#xff0c;希望可以幫到大…

Notepad++插件安裝

方式一&#xff1a;自動安裝&#xff08;有些notepad并不好用&#xff0c;推薦方式二&#xff09;工具欄-》插件-》插件管理如下點擊安裝后會提示&#xff0c;后端安裝&#xff0c;安裝成功后自動啟動&#xff0c;本人使用的v8.6.4的版本&#xff0c;插件基本都無法自動安裝&am…

git pull和git fetch的區別

git pull和git fetch是git版本控制系統中的兩個基本命令&#xff0c;它們都用于從遠程倉庫更新本地倉庫的信息&#xff0c;但執行的具體操作不同。git fetch:git fetch下載遠程倉庫最新的內容到你的本地倉庫&#xff0c;但它并不自動合并或修改你當前的工作。它取回了遠程倉庫的…

Item35:考慮virtual函數以外的其他選擇

在C++中,虛函數是實現多態的傳統方式,但并非唯一選擇。過度依賴虛函數可能導致派生類與基類的強耦合,或難以在運行時靈活切換行為。《Effective C++》Item35指出:應根據場景選擇更合適的替代方案,包括NVI模式、函數指針、策略模式等。本文解析這些方案的原理、適用場景及實…

Vue3 狀態管理新選擇:Pinia 從入門到實戰

一、什么是pinia? 在 Vue3 生態中&#xff0c;狀態管理一直是開發者關注的核心話題。隨著 Vuex 的逐步淡出&#xff0c;Pinia 作為官方推薦的狀態管理庫&#xff0c;憑借其簡潔的 API、強大的功能和對 Vue3 特性的完美適配&#xff0c;成為了新時代的不二之選。今天我們就來深…

Unity相機控制

相機的控制無非移動和旋轉&#xff0c;每種操作各3個軸6個方向&#xff0c;一共12種方式。在某些需要快速驗證的項目或Demo里常常需要絲滑的控制相機調試效果。相機控制雖然不是什么高深的技術&#xff0c;但是要寫的好用還是很磨人的。 鎖定Z軸的旋轉 一個自由的相機可以繞 …

vue2 使用liveplayer加載視頻

vue2 使用liveplayer加載視頻 官網: https://www.liveqing.com/docs/manuals/LivePlayer.html支持WebRTC/MP4播放;支持m3u8/HLS播放;支持HTTP-FLV/WS-FLV/RTMP播放;支持直播和點播播放;支持播放器快照截圖;支持點播多清晰度播放;支持全屏或比例顯示;自動檢測IE瀏覽器兼容播放;支…

JavaScript語法樹簡介:AST/CST/詞法/語法分析/ESTree/生成工具

AST簡介 在平時的開發中&#xff0c;經常會遇到對JavaScript代碼進行檢查或改動的工具&#xff0c;例如ESLint會檢查代碼中的語法錯誤&#xff1b;Prettier會修改代碼的格式&#xff1b;打包工具會將不同文件中的代碼打包在一起等等。這些工具都對JavaScript代碼本身進行了解析…

Java函數式編程之【基本數據類型流】

一、基本數據類型與基本數據的包裝類 在Java編程語言中&#xff0c;int、long和double等基本數據類型都各有它們的包裝類型Integer、Long和Double。 基本數據類型是Java程序語言內置的數據類型&#xff0c;可直接使用。 而包裝類型則歸屬于普通的Java類&#xff0c;是對基本數據…

.NET Core部署服務器

1、以.NET Core5.0為例&#xff0c;在官網下載 下載 .NET 5.0 (Linux、macOS 和 Windows) | .NET 根據自己需求選擇x64還是x86&#xff0c;記住關鍵下載完成還需要下載 Hosting Bundel &#xff0c;否則不成功 2、部署https將ssl證書放在服務器上&#xff0c;雙擊導入&#…

YOLO---04YOLOv3

YOLOV3 論文地址&#xff1a;&#xff1a;【https://arxiv.org/pdf/1804.02767】 YOLOV3 論文中文翻譯地址&#xff1a;&#xff1a;【YOLO3論文中文版_yolo v3論文 中文版-CSDN博客】 YOLOv3 在實時性和精確性在當時都是做的比較好的&#xff0c;并在工業界得到了廣泛應用 …

Qt知識點3『自定義屬性的樣式表失敗問題』

問題1&#xff1a;自定義類中的自定義屬性&#xff0c;如何通過樣式表來賦值除了QT自帶的屬性&#xff0c;我們自定義的類中如果有自定義的靜態屬性&#xff0c;也可以支持樣式表&#xff0c;如下 &#xff1a; Q_PROPERTY(QColor myBorderColor READ getMyBorderColor WRITE s…

RDQS_c和RDQS_t的作用及區別

&#x1f501; LPDDR5 中的 RDQS_t 和 RDQS_c — 復用機制詳解 &#x1f4cc; 基本角色 引腳名 讀操作&#xff08;READ&#xff09;作用 寫操作&#xff08;WRITE&#xff09;作用&#xff08;當啟用Link ECC&#xff09; RDQS_t Read DQS True&#xff1a;與 RDQS_c…

測試分類:詳解各類測試方式與方法

前言&#xff1a;為什么要將測試進行分類呢&#xff1f;軟件測試是軟件生命周期中的?個重要環節&#xff0c;具有較高的復雜性&#xff0c;對于軟件測試&#xff0c;可以從不同的角度加以分類&#xff0c;使開發者在軟件開發過程中的不同層次、不同階段對測試工作進行更好的執…

新手docker安裝踩坑記錄

最近在學習docker&#xff0c;安裝和使用折騰了好久&#xff0c;在這里記錄一下。下載# 依賴安裝 sudo apt update sudo apt install -y \ca-certificates \curl \gnupg \lsb-release# 使用清華鏡像源&#xff08;Ubuntu 24.04 noble&#xff09; echo \"deb [arch$(dpkg …