聊一下 c++ 的std::mutex
std::mutex 是 C++11 引入的一个工具,用来管多线程抢资源的问题,简单又实用。
啥是 std::mutex?
想象你在家吃饭,桌上只有一碗饭,但有俩人(线程)同时伸手抢。没规矩就乱了,可能饭洒了还吃不上。std::mutex 就像个“饭碗锁”,谁拿了锁谁吃饭,别人得等着,吃了放回去再给下一个人。
简单说:std::mutex 是一个互斥锁(Mutex),用来保护共享资源,让多线程安全访问。
为啥用它? 防抢:多线程同时改同一块数据会乱,锁住就安全。 简单:比手动协调线程省事。 标准:C++ 自带,哪儿都能用。
怎么用?
得先包含头文件
- 基本用法
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx; // 定义一个锁
int count = 0; // 共享资源
void increment() {
mtx.lock(); // 上锁
count++; // 改共享数据
std::cout << "Count: " << count << "\n";
mtx.unlock(); // 解锁
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
return 0;
}
输出(顺序可能变):
Count: 1
Count: 2
std::mutex mtx:创建锁。
lock():上锁,没锁住就等着。
unlock():解锁,放手让别人用。
俩线程抢着加 count,锁保证一次只能一个干。
2. 用 RAII(推荐)
手动 lock/unlock 容易忘解锁,C++ 提供了 std::lock_guard,死了自动解:
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
int count = 0;
void increment() {
std::lock_guard<std::mutex> guard(mtx); // 上锁
count++; // 安全操作
std::cout << "Count: " << count << "\n";
} // guard 死了,自动解锁
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
return 0;
}
std::lock_guard:构造时锁上,析构时解开,省心。 输出同上,但更安全。
3. 带条件的锁
如果不想一直等着,可以用 try_lock:
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
int count = 0;
void increment(int id) {
if (mtx.try_lock()) { // 尝试上锁
count++;
std::cout << "线程 " << id << " 成功加: " << count << "\n";
mtx.unlock();
} else {
std::cout << "线程 " << id << " 没抢到锁\n";
}
}
int main() {
std::thread t1(increment, 1);
std::thread t2(increment, 2);
t1.join();
t2.join();
return 0;
}
输出(可能):
线程 1 成功加: 1
线程 2 没抢到锁
try_lock():试着锁,成功返回 true,失败返回 false,不阻塞。
4. 更高级:unique_lock
std::uniquelock 比 lockguard 灵活,能手动解锁:
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
int count = 0;
void increment() {
std::unique_lock<std::mutex> lock(mtx); // 上锁
count++;
lock.unlock(); // 手动解锁
std::cout << "Count: " << count << "\n"; // 解锁后再干别的
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
return 0;
}
std::uniquelock:可以中途解锁,或者延迟锁(deferlock),更自由。
5. 多个锁:防死锁
如果有俩锁,防止线程互相卡死:
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx1, mtx2;
void task1() {
std::lock(mtx1, mtx2); // 一次锁住俩
std::lock_guard<std::mutex> l1(mtx1, std::adopt_lock);
std::lock_guard<std::mutex> l2(mtx2, std::adopt_lock);
std::cout << "任务1 拿到了俩锁\n";
}
void task2() {
std::lock(mtx2, mtx1); // 顺序反着也行
std::lock_guard<std::mutex> l2(mtx2, std::adopt_lock);
std::lock_guard<std::mutex> l1(mtx1, std::adopt_lock);
std::cout << "任务2 拿到了俩锁\n";
}
int main() {
std::thread t1(task1);
std::thread t2(task2);
t1.join();
t2.join();
return 0;
}
注意点
- 别忘解锁: 手动 lock() 一定要配 unlock(),不然卡死。
用 lockguard 或 uniquelock 就不用操心。
- 性能:
锁多了线程会排队,太频繁影响效率。
- 死锁:
俩线程互相等锁会卡死,用 std::lock 或小心顺序。
需要掌握啥?
基本锁:lock() 和 unlock()。
RAII:std::lock_guard 简单安全。
灵活锁:std::unique_lock 手动控制。
试锁:try_lock() 不想等时用。
多锁:std::lock() 防死锁。
场景:保护共享数据,比如计数器、文件。
总结
std::mutex 是 C++ 的锁,管住多线程抢资源。
用法:手动 lock/unlock,或用 lockguard/uniquelock 自动管理。
核心是安全访问共享数据,现代多线程必备。
文档信息
版权声明:可自由转载(请注明转载出处)-非商用-非衍生
发表时间:2025年7月1日 12:16