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

