【C++】互斥锁-①
互斥锁
相比std::lock_guard的优势:
| 功能 | std::lock_guard | std::unique_lock |
| 自动加锁+自动解锁 | 支持 | 支持 |
| 手动加锁/解锁 | 不支持 | 支持 |
| 延迟加锁(defer_lock) | 不支持 | 支持 |
| 条件变量wait支持 | 不支持 | 支持 |
| 可移动(不可复制) | 不可移动 | 可移动,不可复制 |
延迟加锁用法:
① 条件判断后决定是否加锁,例如有些条件根本不需要加锁,就可以延迟决定是否加锁:
void maybe_lock(bool need_lock) {
std::unique_lock<std::mutex> lock(mtx, std::defer_lock);
if (need_lock) {
lock.lock();
// 访问共享数据
} else {
// 不加锁直接返回或做别的事
}
}
void maybe_lock(bool need_lock) {
std::unique_lock<std::mutex> lock(mtx, std::defer_lock);
if (need_lock) {
lock.lock();
// 访问共享数据
} else {
// 不加锁直接返回或做别的事
}
}
② 推迟加锁和手动lock()/unlock()配合,可以控制锁的使用范围:
void custom_lock_region() {
std::unique_lock<std::mutex> lock(mtx, std::defer_lock);
// ... 不加锁做前置工作
lock.lock(); // 开始临界区
// ... 加锁访问共享数据
lock.unlock(); // 提前解锁
// 后面工作不需要锁
}
直接使用mtx.lock()出现异常风险:
void risky() {
mtx.lock();
do_something(); // 这里如果抛异常,mtx 永远不解锁!
mtx.unlock();
}
用std::unique_lock是异常安全的:
void safe() {
std::unique_lock<std::mutex> lock(mtx); // 自动加锁
do_something(); // 即使这里抛异常,析构时 lock 自动解锁
}
示例:线程安全的计数器
#include <iostream>
#include <thread>
#include <mutex>
int counter = 0;
std::mutex counter_mutex;
void increment(int id) {
for (int i = 0; i < 5; ++i) {
std::unique_lock<std::mutex> lock(counter_mutex); // 自动加锁
++counter;
std::cout << "Thread " << id << " incremented counter to " << counter << std::endl;
// 自动解锁在 lock 离开作用域时(即函数体末尾)
}
}
int main() {
std::thread t1(increment, 1);
std::thread t2(increment, 2);
t1.join();
t2.join();
std::cout << "Final counter value: " << counter << std::endl;
return 0;
}
1. 例子:
#include <iostream>
#include <vector>
#include <string>
#include <mutex>
#include <thread>
#include <chrono>
std::mutex log_mutex;
std::vector<std::string> log_buffer;
void log_message(int thread_id, int message_id) {
// 创建 unique_lock,但暂时不加锁
std::unique_lock<std::mutex> lock(log_mutex, std::defer_lock);
// 模拟一些不需要锁的工作
std::this_thread::sleep_for(std::chrono::milliseconds(10));
// 手动加锁
lock.lock();
std::string msg = "Thread " + std::to_string(thread_id) + " - Message " + std::to_string(message_id);
log_buffer.push_back(msg);
// 可以手动解锁早于作用域结束
lock.unlock();
// 模拟后续不依赖锁的工作
std::this_thread::sleep_for(std::chrono::milliseconds(5));
}
int main() {
std::vector<std::thread> threads;
// 启动多个线程写日志
for (int i = 0; i < 5; ++i) {
threads.emplace_back([i]() {
for (int j = 0; j < 3; ++j) {
log_message(i, j);
}
});
}
for (auto& t : threads) {
t.join();
}
// 主线程读取日志(也加锁)
{
std::unique_lock<std::mutex> lock(log_mutex);
std::cout << "Final log:\n";
for (const auto& msg : log_buffer) {
std::cout << msg << "\n";
}
}
return 0;
}
3. 点击【下一步】按钮:

浙公网安备 33010602011771号