C++中unique_lock和lock_guard區(qū)別小結(jié)
在 C++ 中,std::unique_lock
和 std::lock_guard
都屬于標(biāo)準(zhǔn)庫(kù) <mutex>
中的互斥鎖管理工具,用于簡(jiǎn)化互斥鎖的使用并確保線程安全。但它們存在一些顯著區(qū)別,下面為你詳細(xì)介紹:
1.自動(dòng)鎖定與解鎖機(jī)制
1) std::lock_guard
:一個(gè)輕量級(jí)的互斥鎖包裝器,采用了 RAII(資源獲取即初始化)技術(shù)。當(dāng) std::lock_guard
對(duì)象被創(chuàng)建時(shí),它會(huì)自動(dòng)鎖定所關(guān)聯(lián)的互斥鎖;當(dāng)對(duì)象離開(kāi)其作用域時(shí),會(huì)自動(dòng)解鎖該互斥鎖。它的設(shè)計(jì)遵循最小化原則,僅提供最基本的鎖管理功能,沒(méi)有額外的開(kāi)銷。其核心實(shí)現(xiàn)原理可以簡(jiǎn)化為:
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; // 當(dāng) lock_guard 對(duì)象離開(kāi)作用域時(shí),互斥鎖會(huì)自動(dòng)解鎖 } int main() { std::thread t(printMessage); t.join(); return 0; }
2) std::unique_lock
: 同樣基于 RAII 技術(shù),在對(duì)象銷毀時(shí)會(huì)自動(dòng)解鎖互斥鎖。不過(guò),它的鎖定和解鎖操作更加靈活,可以在對(duì)象創(chuàng)建時(shí)選擇不立即鎖定互斥鎖,也可以在對(duì)象生命周期內(nèi)手動(dòng)鎖定和解鎖。unique_lock 是 C++11 標(biāo)準(zhǔn)中引入的更高級(jí)的鎖管理器,設(shè)計(jì)目標(biāo)是提供更靈活的鎖管理能力。其核心接口包括:
class unique_lock { public: // 構(gòu)造時(shí)可選立即加鎖、延遲加鎖或嘗試加鎖 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); // 轉(zhuǎn)移構(gòu)造函數(shù) unique_lock(unique_lock&& other) noexcept; // 手動(dòng)控制接口 voidlock(); booltry_lock(); voidunlock(); // 狀態(tài)查詢 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); // 手動(dòng)鎖定互斥鎖 lock.lock(); std::cout << "This message is protected by unique_lock." << std::endl; // 手動(dòng)解鎖互斥鎖 lock.unlock(); } int main() { std::thread t(printMessage); t.join(); return 0; }
std::unique_lock
允許在對(duì)象生命周期內(nèi)多次手動(dòng)調(diào)用 lock()
、unlock()
和 try_lock()
方法。這在需要在臨界區(qū)內(nèi)進(jìn)行部分操作后暫時(shí)釋放鎖,執(zhí)行一些非關(guān)鍵操作,然后再次鎖定的場(chǎng)景中很有用。如:
#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; // 執(zhí)行部分臨界區(qū)操作 lock.unlock(); std::cout << "Temporarily released the lock." << std::endl; // 執(zhí)行一些非關(guān)鍵操作 lock.lock(); std::cout << "Re - entered critical section." << std::endl; // 繼續(xù)執(zhí)行臨界區(qū)操作 } int main() { std::thread t(work); t.join(); return 0; }
2.靈活性
1)std::lock_guard: 功能相對(duì)單一,缺乏靈活性。一旦創(chuàng)建,就會(huì)立即鎖定互斥鎖,并且在其生命周期內(nèi)無(wú)法手動(dòng)解鎖,只能在對(duì)象離開(kāi)作用域時(shí)自動(dòng)解鎖。
2)std::unique_lock:
具有更高的靈活性。它支持三種鎖定策略:
std::defer_lock_t // 延遲鎖定 std::try_to_lock_t // 嘗試鎖定 std::adopt_lock_t // 接管已鎖定狀態(tài)
- 延遲鎖定(
std::defer_lock
):創(chuàng)建std::unique_lock
對(duì)象時(shí),可以選擇不立即鎖定互斥鎖。這在需要先進(jìn)行一些準(zhǔn)備工作,之后再鎖定互斥鎖的場(chǎng)景中非常有用。如:
#include <iostream> #include <mutex> #include <thread> std::mutex mtx; void work() { std::unique_lock<std::mutex> lock(mtx, std::defer_lock); // 進(jìn)行一些無(wú)需加鎖的準(zhǔn)備工作 std::cout << "Doing some preparation work..." << std::endl; lock.lock(); std::cout << "Critical section entered." << std::endl; // 臨界區(qū)代碼 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
可以嘗試鎖定互斥鎖,如果互斥鎖當(dāng)前已被其他線程鎖定,std::unique_lock
對(duì)象不會(huì)阻塞,而是立即返回,可通過(guò)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; // 臨界區(qū)代碼 } else { std::cout << "Failed to lock the mutex, doing other work." << std::endl; // 執(zhí)行其他不需要鎖定互斥鎖的工作 } } int main() { std::thread t(work); t.join(); return 0; }
3.所有權(quán)轉(zhuǎn)移
std::lock_guard
:
- 不支持所有權(quán)轉(zhuǎn)移,即不能將一個(gè)
std::lock_guard
對(duì)象的互斥鎖所有權(quán)轉(zhuǎn)移給另一個(gè)對(duì)象。
std::unique_lock
:
- 支持所有權(quán)轉(zhuǎn)移,可以通過(guò)移動(dòng)構(gòu)造函數(shù)或移動(dòng)賦值運(yùn)算符將互斥鎖的所有權(quán)從一個(gè)
std::unique_lock
對(duì)象轉(zhuǎn)移到另一個(gè)對(duì)象。這在函數(shù)返回std::unique_lock
對(duì)象或需要在不同作用域之間傳遞鎖的所有權(quán)時(shí)非常有用。
示例代碼如下:
#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
對(duì)象,因?yàn)樵诘却陂g需要釋放和重新獲取鎖。
#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.性能開(kāi)銷
std::lock_guard
:
- 由于其功能簡(jiǎn)單,沒(méi)有額外的狀態(tài)管理,因此性能開(kāi)銷相對(duì)較小,適合用于簡(jiǎn)單的鎖定場(chǎng)景。
std::unique_lock
:
- 為了支持更多的靈活性,
std::unique_lock
需要維護(hù)更多的狀態(tài)信息,因此性能開(kāi)銷相對(duì)較大。在對(duì)性能要求極高且鎖定邏輯簡(jiǎn)單的場(chǎng)景下,使用std::lock_guard
更為合適。
綜上所述,std::lock_guard
適用于簡(jiǎn)單的鎖定場(chǎng)景,追求簡(jiǎn)潔性和較低的性能開(kāi)銷;而 std::unique_lock
則適用于需要更復(fù)雜鎖定邏輯、支持所有權(quán)轉(zhuǎn)移的場(chǎng)景,但會(huì)帶來(lái)一定的性能開(kāi)銷。
到此這篇關(guān)于C++中unique_lock和lock_guard區(qū)別小結(jié)的文章就介紹到這了,更多相關(guān)C++ unique_lock和lock_guard區(qū)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++連接數(shù)據(jù)庫(kù)SqlServer、MySql、Oracle、Access、SQLite、PostgreSQL、Mong
C++是一種通用的編程語(yǔ)言,可以使用不同的庫(kù)和驅(qū)動(dòng)程序來(lái)連接各種數(shù)據(jù)庫(kù),以下是一些示例代碼,演示如何使用?C++?連接?SQL?Server、MySQL、Oracle、ACCESS、SQLite?、?PostgreSQL、MongoDB、Redis數(shù)據(jù)庫(kù)2024-08-08Qt?10進(jìn)制和16進(jìn)制轉(zhuǎn)換的使用示例
在編程過(guò)程中,處理16進(jìn)制字符串與10進(jìn)制數(shù)字之間的轉(zhuǎn)換是很常見(jiàn)的需求,本文主要介紹了Qt?10進(jìn)制和16進(jìn)制轉(zhuǎn)換的使用示例,具有一定的參考價(jià)值,感興趣的可以了解一下2023-09-09C++實(shí)現(xiàn)LeetCode(90.子集合之二)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(90.子集合之二),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07C語(yǔ)言進(jìn)階練習(xí)二叉樹(shù)的遞歸遍歷
樹(shù)是一種重要的非線性數(shù)據(jù)結(jié)構(gòu),直觀地看,它是數(shù)據(jù)元素(在樹(shù)中稱為結(jié)點(diǎn))按分支關(guān)系組織起來(lái)的結(jié)構(gòu),很象自然界中的樹(shù)那樣。樹(shù)結(jié)構(gòu)在客觀世界中廣泛存在,如人類社會(huì)的族譜和各種社會(huì)組織機(jī)構(gòu)都可用樹(shù)形象表示,本篇介紹二叉樹(shù)的遞歸與非遞歸遍歷的方法2022-06-06C++訪問(wèn)者模式模板函數(shù)無(wú)法重載的問(wèn)題解決
本文主要介紹了C++訪問(wèn)者模式模板函數(shù)無(wú)法重載的問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12C++實(shí)現(xiàn)std::set的示例項(xiàng)目
std::set是C++標(biāo)準(zhǔn)庫(kù)中的關(guān)聯(lián)容器,提供有序唯一元素集合,本文就來(lái)介紹一下std::set的具體使用,具有一定的參考價(jià)值,感興趣的可以了解一下2025-02-02Cocos2d-x 3.x入門(mén)教程(一):基礎(chǔ)概念
這篇文章主要介紹了Cocos2d-x 3.x入門(mén)教程(一):基礎(chǔ)概念,本文講解了Director、Scene、Layer、Sprite等內(nèi)容,需要的朋友可以參考下2014-11-11C++ Eigen庫(kù)計(jì)算矩陣特征值及特征向量
這篇文章主要為大家詳細(xì)介紹了C++ Eigen庫(kù)計(jì)算矩陣特征值及特征向量,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-06-06