C++多線程編程 3.互斥量、互斥鎖

目錄

1. 線程安全與互斥鎖(std::mutex)

2. 互斥量死鎖

3.?std::lock_guard

4.?std::unique_lock

(1)示例

?(2)詳細知識點

5. std::this_thread

(1)sleep_for

(2)sleep_until

(3)yield

(4)get_id


直接通過示例講解:

1. 線程安全與互斥鎖(std::mutex

int a = 0;
std::mutex mtx;
void func1()
{for (int i = 0; i < 1000; i++){mtx.lock(); // 加鎖a += 1;mtx.unlock(); // 解鎖}
}

線程安全問題:在多線程環境中,如果多個線程同時訪問和修改同一個共享變量(如這里的?a),可能會導致數據競爭,產生不可預期的結果。

如果多個線程同時訪問同一個變量,并且其中至少有一個線程對該變量進行了寫操作,那么就會出現數據競爭問題。

?

數據競爭可能會導致程序崩潰、產生未定義的結果,或者得到錯誤的結果。

?

為了避免數據競爭問題,需要使用同步機制來確保多個線程之間對共享數據的訪問是安全的。常見的同步機制包括互斥量、條件變量、原子操作等。

std::mutex:互斥鎖是一種同步原語,用于保護共享資源。

mtx.lock()?會嘗試鎖定互斥鎖,如果鎖已經被其他線程持有,當前線程會被阻塞,直到鎖被釋放。

mtx.unlock()?用于釋放鎖,允許其他線程獲取該鎖。

使用方式:在修改共享變量?a?之前調用?mtx.lock()?加鎖,修改完成后調用?mtx.unlock()?解鎖,確保同一時間只有一個線程可以修改?a,從而保證線程安全。

2. 互斥量死鎖

mutex m1, m2;
void func2()
{for (int i = 0; i < 50; i++){m1.lock();m2.lock();m1.unlock();m2.unlock();}
}void func3()
{for (int i = 0; i < 50; i++){m2.lock();m1.lock();m2.unlock();m1.unlock();}
}

死鎖原理:死鎖是指兩個或多個線程在執行過程中,因爭奪資源而造成的一種互相等待的現象。在?func2?中,線程先鎖定?m1?再鎖定?m2;而在?func3?中,線程先鎖定?m2?再鎖定?m1。如果兩個線程同時執行,可能會出現?func2?持有?m1?等待?m2,而?func3?持有?m2?等待?m1?的情況,從而導致死鎖。

解決方法:為了避免死鎖,所有線程應該按照相同的順序獲取鎖,例如都先獲取?m1?再獲取?m2

3.?std::lock_guard

#include <iostream>
#include <thread>
#include <mutex>
#include <vector>std::mutex mtx3;
int b = 0;void fun5()
{for (int i = 0; i < 10000; i++){std::lock_guard<std::mutex> lg(mtx3);b++;}
}int main()
{const int numThreads = 5;  // 定義線程數量std::vector<std::thread> threads;// 創建并啟動線程for (int i = 0; i < numThreads; i++){threads.emplace_back(fun5);}// 等待所有線程執行完畢for (auto& thread : threads){thread.join();}// 輸出最終結果std::cout << "Final value of b: " << b << std::endl;std::cout << "Expected value of b: " << 10000 * numThreads << std::endl;return 0;
}

作用std::lock_guard?是一個 RAII(資源獲取即初始化)風格的類模板,用于自動管理互斥鎖的加鎖和解鎖操作。

工作原理:當創建?std::lock_guard?對象時,它會在構造函數中自動調用互斥鎖的?lock()?方法加鎖;當?std::lock_guard?對象離開其作用域時,它會在析構函數中自動調用互斥鎖的?unlock()?方法解鎖。這樣可以避免手動調用?lock()?和?unlock()?可能導致的忘記解鎖問題,提高代碼的安全性。

4.?std::unique_lock

(1)示例

#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
#include <vector>int c = 0;
std::timed_mutex mtx6;void func6() {for (int i = 0; i < 5000; i++) {std::unique_lock<std::timed_mutex> lg(mtx6, std::defer_lock);std::this_thread::sleep_for(std::chrono::seconds(5));if (lg.try_lock_for(std::chrono::seconds(5))) {c++;lg.unlock();}}
}int main() {const int numThreads = 3;std::vector<std::thread> threads;// 創建并啟動線程for (int i = 0; i < numThreads; i++) {threads.emplace_back(func6);}// 等待所有線程執行完畢for (auto& thread : threads) {thread.join();}// 輸出最終結果std::cout << "Final value of c: " << c << std::endl;std::cout << "Expected value of c: " << 5000 * numThreads << std::endl;return 0;
}

特點std::unique_lock?也是一個用于管理互斥鎖的 RAII 類,但它比?std::lock_guard?更加靈活,包括延遲加鎖、條件變量、超時等

std::unique_lock<std::timed_mutex> lg(mtx6, std::defer_lock);

創建一個?std::unique_lock?對象?lg,用于管理?mtx6?互斥鎖。

參數?defer_lock:在創建?std::unique_lock?對象時,傳遞?defer_lock?參數表示不自動加鎖,需要手動調用?lock()?或?try_lock()?等方法來加鎖。

?

std::this_thread::sleep_for(std::chrono::seconds(5));

當前線程暫停執行 5 秒鐘。

?

lg.try_lock_for(std::chrono::seconds(5));

try_lock_fortry_lock_for?是?std::unique_lock?提供的一個方法,用于嘗試在指定的時間內鎖定互斥鎖。代碼中的含義是:嘗試在 5 秒內鎖定互斥鎖。如果在 5 秒內成功鎖定,則返回?true,否則返回?false

?(2)詳細知識點

1.靈活的鎖定策略

可以在創建?std::unique_lock?對象時選擇是否立即鎖定互斥鎖。例如:

std::mutex mtx;
std::unique_lock<std::mutex> lock1(mtx); // 立即鎖定互斥鎖
std::unique_lock<std::mutex> lock2(mtx, std::defer_lock); // 不立即鎖定互斥鎖

2.?支持鎖的轉移

可以將一個?std::unique_lock?對象的鎖所有權轉移給另一個?std::unique_lock?對象。例如:

std::mutex mtx;
std::unique_lock<std::mutex> lock1(mtx);
std::unique_lock<std::mutex> lock2(std::move(lock1)); // 轉移鎖所有權

3.?支持帶超時的鎖定操作

如果使用的是?std::timed_mutex?或?std::recursive_timed_mutex,可以使用?try_lock_for?和?try_lock_until?方法進行帶超時的鎖定操作。例如:

std::timed_mutex mtx;
std::unique_lock<std::timed_mutex> lock(mtx, std::defer_lock);
if (lock.try_lock_for(std::chrono::seconds(2))) {// 成功鎖定互斥鎖
} else {// 鎖定超時
}

?

5. std::this_thread

std::this_thread?是 C++ 標準庫中的一個命名空間,提供了與當前線程相關的一些實用函數。

(1)sleep_for

使當前線程暫停執行指定的時間段。例如:

std::this_thread::sleep_for(std::chrono::seconds(2)); // 線程暫停 2 秒

(2)sleep_until

使當前線程暫停執行直到指定的時間點。例如:

auto wake_time = std::chrono::steady_clock::now() + std::chrono::seconds(3);
std::this_thread::sleep_until(wake_time); // 線程暫停到指定時間點

(3)yield

當前線程放棄執行權,允許其他線程執行。例如:

std::this_thread::yield(); // 當前線程讓出 CPU 時間片

(4)get_id

返回當前線程的唯一標識符。例如:

std::thread::id this_id = std::this_thread::get_id();
std::cout << "Current thread ID: " << this_id << std::endl;

?

?

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

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

相關文章

【redis】hash基本命令和內部編碼

文章目錄 表示形式命令HSET 和 HGET HEXISTSHDELHKEYSHVALSHGETALLHMGETHLENHSETNXHINCRBYHINCRBYFLOAT命令小結內部編碼 表示形式 Redis 自身已經是鍵值對結構了 Redis 自身的鍵值對就是通過哈希的方式來組織的 把 key 這一層組織完成之后&#xff0c;到了 value 這一層&…

行為模式---策略模式

概念 策略模式是一種行為設計摸是&#xff0c;它的核心思想是將一些列的算法封裝成獨立的對象&#xff0c;并使它們可以相互替換&#xff0c;通過上下文進行調用。 策略模式通過算法抽象為獨立的策略類&#xff0c;客戶端可以根據自身需求選擇不同的策略類來完成任務、這種方…

Selenium 自動化測試學習總結

大概了解一下即可&#xff0c;現在主要用的自動化工具是 playWright&#xff0c;它可以錄制操作。 selenium是老款自動化測試工具&#xff0c;仍有很多可取之處。 安裝&#xff1a; pip install selenium即可。然后下載瀏覽器的驅動包&#xff0c;注意不是瀏覽器&#xff01;…

四層協議攻防手冊:從SYN Flood到UDP反射的深度防御

一、四層協議攻擊類型與特征 攻擊類型協議層特征SYN FloodTCP大量半開連接&#xff0c;SYN_RECV狀態堆積UDP反射放大UDP小請求包觸發大響應&#xff08;如NTP、DNS響應&#xff09;TCP分片攻擊TCP發送異常分片耗盡重組資源連接耗盡攻擊TCP建立大量空閑連接占用端口資源 二、TC…

【社區投稿】深入再談智能指針、AsRef引用與Borrow借用

深入再談智能指針、AsRef引用與Borrow借用 這是一個具有深度的技術主題。每次重溫其理論知識&#xff0c;都會有新的領悟。大約 2 年前&#xff0c;我曾就這一技術方向撰寫過另一篇短文《從類型轉換視角&#xff0c;淺談Deref<Target T>, AsRef<T>, Borrow<T&g…

外層元素旋轉,其包括在內的子元素一并旋轉(不改變旋轉中心),單元測試

思路&#xff1a;外層旋轉后坐標&#xff0c;元素旋轉后坐標&#xff0c;計算偏移坐標 <template><div class"outbox"><label>角度: <input v-model.number"rotate" type"number" /></label><br><div c…

如何在虛擬機上安裝hadoop

與前面java的方式相同安裝好hadoop后進入hadoop的環境變量my_env.sh 輸入#?HADOOP_export HADOOP_HOME /opt/module/hadoop-3.1.3 export PATH$PATH:$HADOOP_HOME/bin export PATH$PATH:$HADOOP_HOME/sbin 再輸入hadoop測試是否安裝成功

WPF-DataGrid的增刪查改

背景&#xff1a;該功能為幾乎所有系統開發都需要使用的功能&#xff0c;現提供簡單的案例。 1、MyCommand using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Input;namespace Wp…

Oracle數據庫存儲結構--物理存儲結構

數據庫存儲結構&#xff1a;分為物理存儲結構和邏輯存儲結構。 物理存儲結構&#xff1a;操作系統層面如何組織和管理數據 邏輯存儲結構&#xff1a;Oracle數據庫內部數據組織和管理數據&#xff0c;數據庫管理系統層面如何組織和管理數據 存儲結構 在Oracle數據庫的存儲結構…

歌詞相關實現

歌詞相關 歌詞數據模型&#xff1a; // Lyric.swift class Lyric: BaseModel {/// 是否是精確到字的歌詞var isAccurate:Bool false/// 所有的歌詞var datum:Array<LyricLine>! }// LyricLine.swift class LyricLine: BaseModel {/// 整行歌詞var data:String!/// 開始…

紡織服裝制造行業現狀 內檢實驗室系統在紡織服裝制造行業的應用

在紡織服裝制造行業&#xff0c;內檢實驗室LIMS系統&#xff08;實驗室信息管理系統&#xff09;已成為提升檢測效率、優化質量控制和滿足行業合規性要求的關鍵工具。隨著行業競爭的加劇和消費者對產品質量要求的提高&#xff0c;紡織服裝制造企業需要更加高效、準確的檢測流程…

K8s 1.27.1 實戰系列(十一)ConfigMap

ConfigMap 是 Kubernetes 中管理非敏感配置的核心資源,通過解耦應用與配置實現靈活性和可維護性。 一、ConfigMap 的核心功能及優勢 ?1、配置解耦 將配置文件(如數據庫地址、日志級別)與容器鏡像分離,支持動態更新而無需重建鏡像。 ?2、多形式注入 ?環境變量:將鍵值…

3分鐘復現 Manus 超強開源項目 OpenManus

文章目錄 前言什么是 OpenManus構建方式環境準備克隆代碼倉庫安裝依賴配置 LLM API運行 OpenManus 效果演示總結個人簡介 前言 近期人工智能領域迎來了一位備受矚目的新星——Manus。Manus 能夠獨立執行復雜的現實任務&#xff0c;無需人工干預。由于限制原因大部分人無法體驗…

從零開始學機器學習——構建一個推薦web應用

首先給大家介紹一個很好用的學習地址:https://cloudstudio.net/columns 今天,我們終于將分類器這一章節學習完活了,和回歸一樣,最后一章節用來構建web應用程序,我們會回顧之前所學的知識點,并新增一個web應用用來讓模型和用戶交互。所以今天的主題是美食推薦。 美食推薦…

【最后203篇系列】014 AI機器人-1

說明 終于開張了&#xff0c;我覺得AI機器人是一件真正正確&#xff0c;具有商業價值的事。 把AI機器人當成一筆生意&#xff0c;我如何做好這筆生意&#xff1f;一端是業務價值&#xff0c;另一端是技術支撐。如何構造高質量的內容和服務&#xff0c;如何確保技術的廣度和深度…

【大模型統一集成項目】如何封裝多個大模型 API 調用

&#x1f31f; 在這系列文章中&#xff0c;我們將一起探索如何搭建一個支持大模型集成項目 NexLM 的開發過程&#xff0c;從 架構設計 到 代碼實戰&#xff0c;逐步搭建一個支持 多種大模型&#xff08;GPT-4、DeepSeek 等&#xff09; 的 一站式大模型集成與管理平臺&#xff…

AI4CODE】3 Trae 錘一個貪吃蛇的小游戲

【AI4CODE】目錄 【AI4CODE】1 Trae CN 錐安裝配置與遷移 【AI4CODE】2 Trae 錘一個 To-Do-List 這次還是采用 HTML/CSS/JAVASCRIPT 技術棧 Trae 錘一個貪吃蛇的小游戲。 1 環境準備 創建一個 Snake 的子文件夾&#xff0c;清除以前的會話記錄。 2 開始構建 2.1 輸入會…

【簡答題002】Java變量簡答題

博主會經常補充完善這里面問題的答案。希望可以得到大家的一鍵三連支持&#xff0c;你的鼓勵是我堅持下去的最大動力&#xff01;謝謝&#xff01; 001 什么是Java變量&#xff1f; Java變量是用來存儲數據并在程序中引用的命名空間。 002 Java變量有哪些類型&#xff1f; J…

從零開發Chrome廣告攔截插件:開發、打包到發布全攻略

從零開發Chrome廣告攔截插件&#xff1a;開發、打包到發布全攻略 想打造一個屬于自己的Chrome插件&#xff0c;既能攔截煩人的廣告&#xff0c;又能優雅地發布到Chrome Web Store&#xff1f;別擔心&#xff0c;這篇教程將帶你從零開始&#xff0c;動手開發一個功能強大且美觀…

基于騰訊云高性能HAI-CPU的跨境電商客服助手全鏈路解析

跨境電商的背景以及痛點 根據Statista數據&#xff0c;2025年全球跨境電商市場規模預計達6.57萬億美元&#xff0c;年增長率保持在12.5% 。隨著平臺規則趨嚴&#xff08;如亞馬遜封店潮&#xff09;&#xff0c;更多賣家選擇自建獨立站&#xff0c;2024年獨立站占比已達35%。A…