std::shared_mutex。std::mutex和std::recursive_mutex是什么锁
| 锁类型 | 类型 | 核心特性 | 适用场景 |
|---|---|---|---|
std::shared_mutex |
读写锁 | 读共享、写独占 | 读多写少 |
std::mutex |
普通互斥锁 | 完全独占,不可递归 | 通用场景(90%的情况) |
std::recursive_mutex |
递归互斥锁 | 同一线程可重复加锁 | 递归函数、嵌套调用 |
详细对比
1. std::shared_mutex ------ 读写锁(C++17)
| 特性 | 说明 |
|---|---|
| 读模式 | 多个线程可同时持有共享锁,并发读取 |
| 写模式 | 只有一个线程可持有独占锁,写时禁止任何读 |
| 适用场景 | 读多写少(如配置缓存、路由表、DNS缓存) |
| 性能 | 读并发高,但写操作开销比 mutex 大 |
| RAII工具 | std::shared_lock(读)、std::unique_lock(写) |
cpp
std::shared_mutex rw_mutex;
std::map<int, int> cache;
// 读操作:多个线程可并发
int read(int key) {
std::shared_lock lock(rw_mutex); // 共享锁
return cache[key];
}
// 写操作:独占
void write(int key, int val) {
std::unique_lock lock(rw_mutex); // 独占锁
cache[key] = val;
}
2. std::mutex ------ 普通互斥锁(C++11)
| 特性 | 说明 |
|---|---|
| 独占性 | 完全独占,同一时间只有一个线程能持有 |
| 递归 | 不支持,同一线程重复 lock() 会导致死锁 |
| 适用场景 | 90%的常规多线程场景 |
| 性能 | 最基础、性能最高 |
| RAII工具 | std::lock_guard、std::unique_lock |
cpp
std::mutex mtx;
int counter = 0;
void increment() {
std::lock_guard lock(mtx); // 自动加锁解锁
++counter;
}
3. std::recursive_mutex ------ 递归互斥锁(C++11)
| 特性 | 说明 |
|---|---|
| 独占性 | 独占,但同一线程可重复加锁 |
| 递归 | 支持,内部维护计数器,加锁几次就要解锁几次 |
| 适用场景 | 递归函数、嵌套调用中需要加锁的场景 |
| 性能 | 比 mutex 略低(需维护线程ID和计数) |
| 注意 | 容易掩盖设计缺陷,能不用就不用 |
cpp
std::recursive_mutex rec_mtx;
void funcA() {
std::lock_guard lock(rec_mtx); // 第一次加锁
funcB(); // 内部再次加锁,不会死锁
}
void funcB() {
std::lock_guard lock(rec_mtx); // 第二次加锁(同一线程)
}
对比总结
| 维度 | std::mutex |
std::recursive_mutex |
std::shared_mutex |
|---|---|---|---|
| C++版本 | C++11 | C++11 | C++17 |
| 独占性 | ✅ 独占 | ✅ 独占 | ✅ 写独占,❌ 读共享 |
| 递归 | ❌ 不支持 | ✅ 支持 | ❌ 不支持 |
| 读并发 | ❌ 不支持 | ❌ 不支持 | ✅ 支持 |
| 性能 | 最高 | 略低 | 读场景高,写场景低 |
| RAII工具 | lock_guard / unique_lock |
lock_guard / unique_lock |
shared_lock(读) / unique_lock(写) |
| 适用场景 | 通用 | 递归/嵌套调用 | 读多写少 |
选择建议
- 默认首选 :
std::mutex+std::lock_guard - 读多写少 :
std::shared_mutex+std::shared_lock(读)/std::unique_lock(写) - 递归调用 :
std::recursive_mutex(但优先考虑重构代码避免递归加锁)