C++中unique_lock和lock_guard區別

目錄

1.自動鎖定與解鎖機制

2.靈活性

3.所有權轉移

4.可與條件變量配合使用

5.性能開銷


在 C++ 中,std::unique_lock?和?std::lock_guard?都屬于標準庫?<mutex>?中的互斥鎖管理工具,用于簡化互斥鎖的使用并確保線程安全。但它們存在一些顯著區別,下面為你詳細介紹:

1.自動鎖定與解鎖機制

1) std::lock_guard:一個輕量級的互斥鎖包裝器,采用了 RAII(資源獲取即初始化)技術。當?std::lock_guard?對象被創建時,它會自動鎖定所關聯的互斥鎖;當對象離開其作用域時,會自動解鎖該互斥鎖。它的設計遵循最小化原則,僅提供最基本的鎖管理功能,沒有額外的開銷。其核心實現原理可以簡化為:

template<classMutex>
classlock_guard?{
public:explicitlock_guard(Mutex& m)?: mutex(m) {mutex.lock();}~lock_guard() {mutex.unlock();}lock_guard(const?lock_guard&) =?delete;lock_guard&?operator=(const?lock_guard&) =?delete;private:Mutex& mutex;
};

????????示例代碼如下:

#include <iostream>
#include <mutex>
#include <thread>std::mutex mtx;void printMessage() {std::lock_guard<std::mutex> lock(mtx);std::cout << "This message is protected by lock_guard." << std::endl;// 當 lock_guard 對象離開作用域時,互斥鎖會自動解鎖
}int main() {std::thread t(printMessage);t.join();return 0;
}

2)?std::unique_lock:?同樣基于 RAII 技術,在對象銷毀時會自動解鎖互斥鎖。不過,它的鎖定和解鎖操作更加靈活,可以在對象創建時選擇不立即鎖定互斥鎖,也可以在對象生命周期內手動鎖定和解鎖。unique_lock 是 C++11 標準中引入的更高級的鎖管理器,設計目標是提供更靈活的鎖管理能力。其核心接口包括:

class?unique_lock?{
public:// 構造時可選立即加鎖、延遲加鎖或嘗試加鎖unique_lock(mutex_type& m, std::defer_lock_t)?noexcept;unique_lock(mutex_type& m, std::try_to_lock_t);unique_lock(mutex_type& m, std::adopt_lock_t);// 轉移構造函數unique_lock(unique_lock&& other)?noexcept;// 手動控制接口voidlock();booltry_lock();voidunlock();// 狀態查詢explicitoperatorbool()constnoexcept;boolowns_lock()constnoexcept;
};

    ? ? ? ? 示例代碼如下:

    #include <iostream>
    #include <mutex>
    #include <thread>std::mutex mtx;void printMessage() {std::unique_lock<std::mutex> lock(mtx, std::defer_lock);// 手動鎖定互斥鎖lock.lock();std::cout << "This message is protected by unique_lock." << std::endl;// 手動解鎖互斥鎖lock.unlock();
    }int main() {std::thread t(printMessage);t.join();return 0;
    }

    std::unique_lock?允許在對象生命周期內多次手動調用?lock()unlock()?和?try_lock()?方法。這在需要在臨界區內進行部分操作后暫時釋放鎖,執行一些非關鍵操作,然后再次鎖定的場景中很有用。如:

    #include <iostream>
    #include <mutex>
    #include <thread>std::mutex mtx;void work() {std::unique_lock<std::mutex> lock(mtx);std::cout << "Entered critical section." << std::endl;// 執行部分臨界區操作lock.unlock();std::cout << "Temporarily released the lock." << std::endl;// 執行一些非關鍵操作lock.lock();std::cout << "Re - entered critical section." << std::endl;// 繼續執行臨界區操作
    }int main() {std::thread t(work);t.join();return 0;
    }

    2.靈活性

    1)std::lock_guard:?功能相對單一,缺乏靈活性。一旦創建,就會立即鎖定互斥鎖,并且在其生命周期內無法手動解鎖,只能在對象離開作用域時自動解鎖。

    2)std::unique_lock:具有更高的靈活性。它支持三種鎖定策略:

    std::defer_lock_t? ?// 延遲鎖定
    std::try_to_lock_t??// 嘗試鎖定
    std::adopt_lock_t? ?// 接管已鎖定狀態
    • 延遲鎖定(std::defer_lock:創建?std::unique_lock?對象時,可以選擇不立即鎖定互斥鎖。這在需要先進行一些準備工作,之后再鎖定互斥鎖的場景中非常有用。如:
    #include <iostream>
    #include <mutex>
    #include <thread>std::mutex mtx;void work() {std::unique_lock<std::mutex> lock(mtx, std::defer_lock);// 進行一些無需加鎖的準備工作std::cout << "Doing some preparation work..." << std::endl;lock.lock();std::cout << "Critical section entered." << std::endl;// 臨界區代碼lock.unlock();std::cout << "Critical section exited." << std::endl;
    }int main() {std::thread t(work);t.join();return 0;
    }
    • 嘗試鎖定(std::try_to_lock:使用?std::try_to_lock?可以嘗試鎖定互斥鎖,如果互斥鎖當前已被其他線程鎖定,std::unique_lock?對象不會阻塞,而是立即返回,可通過?owns_lock()?方法判斷是否成功鎖定。如:
    #include <iostream>
    #include <mutex>
    #include <thread>std::mutex mtx;void work() {std::unique_lock<std::mutex> lock(mtx, std::try_to_lock);if (lock.owns_lock()) {std::cout << "Successfully locked the mutex." << std::endl;// 臨界區代碼} else {std::cout << "Failed to lock the mutex, doing other work." << std::endl;// 執行其他不需要鎖定互斥鎖的工作}
    }int main() {std::thread t(work);t.join();return 0;
    }

    3.所有權轉移

    • std::lock_guard
      • 不支持所有權轉移,即不能將一個?std::lock_guard?對象的互斥鎖所有權轉移給另一個對象。
    • std::unique_lock
      • 支持所有權轉移,可以通過移動構造函數或移動賦值運算符將互斥鎖的所有權從一個?std::unique_lock?對象轉移到另一個對象。這在函數返回?std::unique_lock?對象或需要在不同作用域之間傳遞鎖的所有權時非常有用。
      • 示例代碼如下:
    #include <iostream>
    #include <mutex>
    #include <thread>std::mutex mtx;std::unique_lock<std::mutex> getLock() {std::unique_lock<std::mutex> lock(mtx);return std::move(lock);
    }void printMessage() {std::unique_lock<std::mutex> lock = getLock();std::cout << "This message is protected by transferred unique_lock." << std::endl;
    }int main() {std::thread t(printMessage);t.join();return 0;
    }

    4.可與條件變量配合使用

    std::unique_lock?能夠與?std::condition_variable?一起使用,std::condition_variable?的?wait()wait_for()?和?wait_until()?等方法要求傳入?std::unique_lock?對象,因為在等待期間需要釋放和重新獲取鎖。

    #include <iostream>
    #include <mutex>
    #include <condition_variable>
    #include <thread>std::mutex mtx;
    std::condition_variable cv;
    bool ready = false;void worker() {std::unique_lock<std::mutex> lock(mtx);cv.wait(lock, []{ return ready; });std::cout << "Worker thread is working." << std::endl;
    }int main() {std::thread t(worker);{std::lock_guard<std::mutex> lock(mtx);ready = true;}cv.notify_one();t.join();return 0;
    }

    5.性能開銷

    • std::lock_guard
      • 由于其功能簡單,沒有額外的狀態管理,因此性能開銷相對較小,適合用于簡單的鎖定場景。
    • std::unique_lock
      • 為了支持更多的靈活性,std::unique_lock?需要維護更多的狀態信息,因此性能開銷相對較大。在對性能要求極高且鎖定邏輯簡單的場景下,使用?std::lock_guard?更為合適。

    綜上所述,std::lock_guard?適用于簡單的鎖定場景,追求簡潔性和較低的性能開銷;而?std::unique_lock?則適用于需要更復雜鎖定邏輯、支持所有權轉移的場景,但會帶來一定的性能開銷。

    推薦閱讀

    深入理解C++中的鎖

    C++慣用法之RAII思想: 資源管理

    Qt之條件變量QWaitCondition詳解(從使用到原理分析全)

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

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

    相關文章

    Nvidia顯卡架構演進

    1 簡介 顯示卡&#xff08;英語&#xff1a;Display Card&#xff09;簡稱顯卡&#xff0c;也稱圖形卡&#xff08;Graphics Card&#xff09;&#xff0c;是個人電腦上以圖形處理器&#xff08;GPU&#xff09;為核心的擴展卡&#xff0c;用途是提供中央處理器以外的微處理器幫…

    下載electron 22.3.27 源碼錯誤集錦

    下載步驟同 electron源碼下載及編譯_electron源碼編譯-CSDN博客 問題1 從github 下載 dugite超時&#xff0c;原因沒有找到 Validation failed. Expected 8ea2d0d3c9d9e4615069913207371ffe892dc10fb93975972f2f6e668f2e3b3a but got e3b0c44298fc1c149afbf4c8996fb92427ae41e…

    洛谷P1120 小木棍

    #算法/進階搜索 思路: 首先,最初始想法,將我們需要枚舉的長木棍個數計算出來,在dfs中,我們先判斷,此時枚舉這根長木棍需要的長度是否為0,如果為0,我們就枚舉下一個根木棍,接著再判斷,此時仍需要枚舉的木棍個數是否為0,如果為0,代表我們這種方案可行,直接打印長木棍長度,接著我們…

    Linux教程-常用命令系列二

    文章目錄 1. 系統管理常用命令1. useradd - 創建用戶賬戶功能基本用法常用選項示例 2. passwd - 管理用戶密碼功能基本用法常用選項示例 3. kill - 終止進程功能基本用法常用信號示例 4. date - 顯示和設置系統時間功能基本用法常用選項時間格式示例 5. bc - 高精度計算器功能基…

    18、TimeDiff論文筆記

    TimeDiff **1. 背景與動機****2. 擴散模型基礎****3. TimeDiff 模型****3.1 前向擴散過程****3.2 后向去噪過程** 4、TimeDiff&#xff08;架構&#xff09;原理訓練推理其他關鍵點解釋 DDPM&#xff08;相關數學&#xff09;1、正態分布2、條件概率1. **與多個條件相關**&…

    整合SSM——(SpringMVC+Spring+Mybatis)

    目錄 SSM整合 創建項目 導入依賴 配置文件 SpringConfig MyBatisConfig JdbcConfig ServletConfig SpringMvcConfig 功能模塊 測試 業務層接口測試 控制層測試 SSM是Java Web開發中常用的三個主流框架組合的縮寫&#xff0c;分別對應Spring、Spring MVC、MyBatis…

    P1042【深基8,例1】乒乓球

    【題目背景】國際乒聯現在主席沙拉拉自從上任以來就立志于推行一系列改革&#xff0c;以推動乒乓球運動在全球的普及。其中 11 分制改革引起了很大的爭議&#xff0c;有一部分球員因為無法適應新規則只能選擇退役。華華就是其中一位&#xff0c;他退役之后走上了乒乓球研究工作…

    ubuntu24.04上使用qemu和buildroot模擬vexpress-ca9開發板構建嵌入式arm linux環境

    1 準備工作 1.1 安裝qemu 在ubuntu系統中使用以下命令安裝qemu。 sudo apt install qemu-system-arm 安裝完畢后&#xff0c;在終端輸入: qemu- 后按TAB鍵&#xff0c;彈出下列命令證明安裝成功。 1.2 安裝arm交叉編譯工具鏈 sudo apt install gcc-arm-linux-gnueabihf 安裝之…

    用 R 語言打造交互式敘事地圖:講述黃河源區生態變化的故事

    目錄 ?? 項目背景:黃河源頭的生態變遷 ?? 技術棧介紹 ??? 最終效果預覽 ?? 項目構建步驟 1?? 數據準備 2?? 構建 Leaflet 地圖 3?? 使用 scrollama 實現滾動觸發事件 4?? 使用 R Markdown / Quarto 打包發布 ?? 效果展示截圖 ?? 完整代碼倉庫 …

    CTF--秋名山車神

    一、原網頁&#xff1a; 二、步驟&#xff1a; 1.嘗試用計算器計算&#xff1a; 計算器溢出&#xff0c;無法正常計算 2.使用python計算&#xff1a; 得出計算結果為&#xff1a;1864710043732437134701060769 3.多次刷新頁面&#xff1a; 發現變量為value&#xff0c;要用pos…

    CRC實戰寶典:從原理到代碼,全面攻克循環冗余校驗

    CRC實戰寶典&#xff1a;從原理到代碼&#xff0c;全面攻克循環冗余校驗 github開源&#xff1a;CRC軟硬件協同測試項目 CRC 簡介 CRC&#xff08;循環冗余校驗&#xff09;是一種強大的錯誤檢測技術&#xff0c;廣泛應用于數字網絡和存儲系統。它是確保數據完整性的重要方法…

    【大模型】DeepSeek + Coze 打造個人專屬AI智能體使用詳解

    目錄 一、前言 二、AI智能體介紹 2.1 什么是AI智能體 2.2 AI智能體核心能力 2.3 AI智能應用場景 三、coze 介紹 3.1 coze是什么 3.1.1 平臺概述 3.1.2 平臺適用人群 3.2 平臺核心功能 3.3 coze可以做什么 3.4 為什么選擇coze 四、coze 搭建AI智能體操作實踐 4.1 搭…

    MySQL入門:數據表的創建

    ?今天我們來介紹一下除HTML外的另一種語言&#xff1a;MySQL語言&#xff1b; MySQL&#xff1a;即一種用于管理和處理關系數據庫的標準語言。要用于執行查詢、更新、管理數據庫中的數據以及定義和操作數據庫結構。 接下來我會逐一介紹它的作用以及其中數據表&#xff0c;數據…

    [圖論]生成樹 引言

    生成樹 引言 生成樹&#xff1a;一個連通圖的生成樹是該圖的一個極小連通子圖。生成樹中含有圖中全部(設 V V V個)頂點及構成一棵樹的 V ? 1 V-1 V?1條邊&#xff0c;且生成樹中不應有環。最小生成樹(MST)&#xff1a;圖的所有生成樹中&#xff0c;邊權之和最小的生成樹。顯…

    AI調試工具有哪些?

    一、深度學習框架專用調試工具 TensorBoard ? 功能&#xff1a;實時監控訓練指標&#xff08;損失值、準確率&#xff09;、可視化神經網絡結構、分析參數分布和梯度信息 ? 適用框架&#xff1a;TensorFlow、PyTorch&#xff08;通過插件&#xff09; ? 特點&#xff1a;支持…

    深入理解 MCP 協議:開啟 AI 交互新時代

    深入理解 MCP 協議&#xff1a;開啟 AI 交互新時代&#x1f680; 在當今人工智能蓬勃發展的時代&#x1f310;&#xff0c;大型語言模型&#xff08;LLM&#xff09;已經在眾多領域展現出了強大的能力&#xff0c;令人驚嘆&#x1f44f;&#xff01;然而&#xff0c;傳統的 LLM…

    微信、抖音、小紅書emoji符號大全

    1、Emoji 日常符號 &#x1f463;&#x1f440;&#x1f441;?&#x1f444;&#x1f48b;&#x1f442;&#x1f9bb;&#x1f443;&#x1f445;&#x1f9e0;&#x1fac0;&#x1fac1;&#x1f9b7;&#x1f9b4;&#x1f4aa;&#x1f9be;&#x1f9bf;&#x1f9b5;&a…

    【嵌入式】——Linux系統遠程操作和程序編譯

    目錄 一、虛擬機配置網絡設置 二、使用PuTTY登錄新建的賬戶 1、在ubuntu下開啟ssh服務 2、使用PuTTY連接 三、樹莓派實現遠程登錄 四、樹莓派使用VNC viewer登錄 五、Linux使用talk聊天程序 1、使用linux自帶的talk命令 2、使用c語言編寫一個talk程序 一、虛擬機配置網絡…

    春和景明-C語言簡單代碼

    題目要求&#xff1a; 請在centOS Linux中編寫一個C語言程序實現如下功能&#xff1a; 同時創建100個用戶&#xff0c;用戶的賬戶名稱為&#xff1a;Student01 Student02 … Student100;設置每個用戶的初始密碼為&#xff1a;stud123456請用gcc編譯C的源代碼&#xff0c;生…

    設計模式之工廠模式(factory pattern):在商品對象創建系統中的應用

    目錄 一、設計思路 1. 簡單工廠模式 2. 工廠方法模式 3. 抽象工廠模式 二、UML類圖&#xff08;PlantUML格式&#xff09; 1.簡單工廠模式 2.工廠方法模式 3.抽象工廠模式 三、實現過程與結果 1. 簡單工廠模式 2. 工廠方法模式 3. 抽象工廠模式 四、總結 在面向對…