C++ 17 std::shared_mutex

C++ 17 std::shared_mutex

std::shared_mutex 可以把它理解成标准库提供的“读写锁”。
它允许多个线程同时持有共享锁进行只读访问,但写入时必须独占。

1. 为什么需要 shared_mutex?

普通 std::mutex 的特点是:

  • 同一时刻只能有一个线程持锁
  • 不区分读和写

如果某个共享资源大部分时候只是读取,只有少数时候写入,那么普通互斥锁就会显得有点保守。
这时 shared_mutex 会更合适。

2. 两种加锁方式

2.1 独占锁

写操作使用独占锁:

1
std::unique_lock<std::shared_mutex> lock(mtx);

2.2 共享锁

读操作使用共享锁:

1
std::shared_lock<std::shared_mutex> lock(mtx);

多个读线程可以同时持有共享锁。

3. 基本示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <shared_mutex>
#include <thread>
using namespace std;

shared_mutex mtx;
int value = 0;

void readTask()
{
shared_lock<shared_mutex> lock(mtx);
cout << "read value: " << value << endl;
}

void writeTask()
{
unique_lock<shared_mutex> lock(mtx);
++value;
cout << "write value: " << value << endl;
}

int main()
{
thread t1(readTask);
thread t2(readTask);
thread t3(writeTask);

t1.join();
t2.join();
t3.join();
return 0;
}

4. 适合什么场景?

4.1 读多写少

比如:

  • 配置读取
  • 缓存查询
  • 路由表读取
  • 字典/索引访问

如果读取远多于修改,shared_mutex 比普通 mutex 更有发挥空间。

4.2 不适合写特别频繁的场景

如果写入很多,独占锁争用仍然会明显,这时收益就未必大。

5. 和 mutex 的区别

mutex

  • 简单直接
  • 所有访问统一排队

shared_mutex

  • 支持共享读
  • 写入仍然独占
  • 适合读多写少

6. 使用时的注意点

6.1 读锁里不要偷偷修改数据

既然拿的是共享锁,那就应该只做只读操作。

6.2 不要以为它一定更快

锁本身的实现更复杂,如果场景并不符合“读多写少”,那性能未必更好。

6.3 仍然要注意锁粒度

即使换成 shared_mutex,锁范围过大一样会影响并发性能。

总结

std::shared_mutex 给标准库补上了一个很实用的并发工具。
当共享资源主要是读取,偶尔写入时,它比 std::mutex 更适合;但如果场景并不符合这个前提,就没必要强行上读写锁。关键还是看访问模式是否真的“读多写少”。