C++ 線程互斥鎖 lock_guard的基本用法
std::lock_guard是 C++11 標(biāo)準(zhǔn)庫(kù)提供的RAII 風(fēng)格的互斥鎖封裝類,核心目的是自動(dòng)管理互斥鎖的加鎖 / 解鎖,從根本上避免 “忘記解鎖導(dǎo)致死鎖”“異常導(dǎo)致鎖無法釋放” 這類低級(jí)且致命的錯(cuò)誤。
一、先理解核心:RAII 設(shè)計(jì)思想
lock_guard的底層是RAII(資源獲取即初始化) 機(jī)制 —— 簡(jiǎn)單說:
- 構(gòu)造時(shí)獲取資源:
lock_guard對(duì)象創(chuàng)建時(shí),自動(dòng)調(diào)用互斥鎖的lock()方法加鎖; - 析構(gòu)時(shí)釋放資源:
lock_guard對(duì)象銷毀時(shí)(比如出作用域),自動(dòng)調(diào)用互斥鎖的unlock()方法解鎖。
這種 “自動(dòng)性” 是解決多線程鎖管理問題的關(guān)鍵,不用再手動(dòng)記著unlock()。
二、lock_guard的基本用法(對(duì)比手動(dòng)加解鎖)
先看錯(cuò)誤的手動(dòng)加解鎖(容易出問題):
#include <mutex>
std::mutex mtx;
void wrong_func() {
mtx.lock(); // 手動(dòng)加鎖
// 臨界區(qū)操作:修改共享資源
int a = 10;
// 忘記解鎖 → 死鎖!
// 或如果臨界區(qū)拋出異常,unlock()永遠(yuǎn)執(zhí)行不到 → 死鎖!
// mtx.unlock();
}再看正確的 lock_guard 用法(自動(dòng)解鎖):
#include <mutex>
std::mutex mtx;
void right_func() {
// 創(chuàng)建lock_guard對(duì)象時(shí),自動(dòng)調(diào)用mtx.lock()
std::lock_guard<std::mutex> lock(mtx);
// 臨界區(qū):安全操作共享資源
int a = 10;
} // lock_guard對(duì)象出作用域,析構(gòu)時(shí)自動(dòng)調(diào)用mtx.unlock()
// 即使臨界區(qū)拋出異常,析構(gòu)函數(shù)也會(huì)執(zhí)行 → 必解鎖!三、lock_guard的核心特性
1. 不可拷貝、不可移動(dòng)
lock_guard被設(shè)計(jì)為 “只能在當(dāng)前作用域使用”,禁止拷貝 / 移動(dòng),避免鎖的管理權(quán)被非法轉(zhuǎn)移:
std::lock_guard<std::mutex> lock1(mtx); // std::lock_guard<std::mutex> lock2 = lock1; // 編譯錯(cuò)誤:禁止拷貝 // std::lock_guard<std::mutex> lock3(std::move(lock1)); // 編譯錯(cuò)誤:禁止移動(dòng)
2. 作用域決定解鎖時(shí)機(jī)
lock_guard的解鎖時(shí)機(jī)完全由作用域控制,你可以通過{}手動(dòng)限定作用域,精準(zhǔn)控制解鎖時(shí)機(jī):
void func() {
{
std::lock_guard<std::mutex> lock(mtx);
// 短臨界區(qū):只保護(hù)必要的代碼
shared_data = 100;
} // 此處提前解鎖,不影響后續(xù)非臨界區(qū)代碼
// 非臨界區(qū):無需持鎖,提升并發(fā)效率
sleep(1);
}3. 輕量級(jí)、無額外開銷
lock_guard是極簡(jiǎn)封裝,沒有額外的成員函數(shù)(比如unlock()/lock()),運(yùn)行時(shí)幾乎無性能損耗,適合簡(jiǎn)單的臨界區(qū)保護(hù)。
4. 異常安全
這是lock_guard最核心的優(yōu)勢(shì)之一:即使臨界區(qū)拋出異常,C++ 的異常機(jī)制會(huì)保證局部對(duì)象的析構(gòu)函數(shù)執(zhí)行,從而確保鎖被釋放:
void func_with_exception() {
std::lock_guard<std::mutex> lock(mtx);
// 臨界區(qū)拋出異常
throw std::runtime_error("出錯(cuò)了");
// 無需手動(dòng)unlock,析構(gòu)函數(shù)會(huì)處理
}
int main() {
try {
func_with_exception();
} catch (...) {
// 捕獲異常后,鎖已經(jīng)被釋放,其他線程可正常獲取
}
return 0;
}四、lock_guardvsunique_lock(選型參考)
lock_guard是 “輕量版” 鎖管理,std::unique_lock是 “功能版”,兩者的核心區(qū)別如下:
| 特性 | std::lock_guard | std::unique_lock |
|---|---|---|
| 自動(dòng)加解鎖 | ? 支持 | ? 支持 |
手動(dòng)解鎖(unlock()) | ? 不支持 | ? 支持 |
配合條件變量(cv.wait()) | ? 不支持 | ? 支持 |
| 性能 | 極致輕量 | 略重(有額外狀態(tài)) |
| 適用場(chǎng)景 | 簡(jiǎn)單臨界區(qū)保護(hù) | 復(fù)雜同步(如條件變量、手動(dòng)控制解鎖) |
簡(jiǎn)單說:
- 只要是 “加鎖后,作用域結(jié)束解鎖” 的簡(jiǎn)單場(chǎng)景,優(yōu)先用
lock_guard(輕量、高效); - 如果需要手動(dòng)解鎖、配合條件變量(比如
cv.wait()需要解鎖后阻塞),用unique_lock。
五、完整示例:lock_guard 保護(hù)共享資源
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
std::mutex mtx;
int shared_count = 0; // 共享資源
// 線程函數(shù):累加共享變量
void increment(int n) {
for (int i = 0; i < n; ++i) {
// lock_guard自動(dòng)加鎖/解鎖
std::lock_guard<std::mutex> lock(mtx);
shared_count++;
// 出循環(huán)迭代的作用域,自動(dòng)解鎖
}
}
int main() {
std::vector<std::thread> threads;
// 創(chuàng)建10個(gè)線程,每個(gè)線程累加1000次
for (int i = 0; i < 10; ++i) {
threads.emplace_back(increment, 1000);
}
// 等待所有線程結(jié)束
for (auto& t : threads) {
t.join();
}
// 正確輸出10000,無數(shù)據(jù)錯(cuò)亂
std::cout << "最終count值:" << shared_count << std::endl;
return 0;
}總結(jié)
std::lock_guard是 C++11 的 RAII 鎖封裝,構(gòu)造加鎖、析構(gòu)解鎖,核心解決 “忘記解鎖 / 異常導(dǎo)致鎖泄漏” 的問題;- 輕量級(jí)、異常安全、不可拷貝,適合簡(jiǎn)單臨界區(qū)的線程安全保護(hù);
- 解鎖時(shí)機(jī)由作用域決定,可通過
{}手動(dòng)縮小作用域,提升并發(fā)效率; - 復(fù)雜同步場(chǎng)景(如條件變量)用
unique_lock,簡(jiǎn)單場(chǎng)景優(yōu)先用lock_guard。
到此這篇關(guān)于C++ 線程互斥鎖 lock_guard的基本用法的文章就介紹到這了,更多相關(guān)C++ 線程互斥鎖 lock_guard內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++小利器之std::bind參數(shù)綁定包裝器的使用詳解
從 C++11 開始,標(biāo)準(zhǔn)庫(kù)提供了 std::bind 用于綁定函數(shù) f 和調(diào)用參數(shù),返回一個(gè)新可調(diào)用函數(shù)對(duì)象 fn,下面就跟隨小編一起深入了解一下std::bind的具體使用吧2023-12-12
C++實(shí)現(xiàn)超市商品管理系統(tǒng)最新版
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)超市商品管理系統(tǒng)最新版,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06
Qt 中線程池QRunnable和QThreadPool的使用
本文主要介紹了Qt 中的線程池QRunnable和QThreadPool的使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-07-07
C語(yǔ)言實(shí)現(xiàn)修改文本文件中特定行的實(shí)現(xiàn)代碼
最近由于項(xiàng)目需要實(shí)現(xiàn)修改文件的功能,所以,博主認(rèn)真查閱了一些資料,但是,很遺憾,并沒有太多的收獲2013-06-06
C語(yǔ)言實(shí)現(xiàn)字符串字符反向排列的方法詳解
這篇文章主要為大家分享了幾種通過C語(yǔ)言實(shí)現(xiàn)字符串字符反向排列(不是逆序打?。┑姆椒ǎ闹械氖纠a講解詳細(xì),感興趣的小伙伴可以了解一下2022-05-05
C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的三子棋
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的三子棋,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-11-11

