「C++ 多线程」std::recursive_mutex 基本用法
文章大图来源:pixiv_id=123093870
1 std::recursive_mutex 基本概念
std::recursive_mutex
是 C++ 11 引入的一种 独占 且 递归 的互斥量类型,用于控制多个线程对共享资源的并发互斥访问。
std::recursive_mutex
包含了 std::mutex
的基本功能,包括 lock()
和 unlock()
函数进行加锁和解锁、try_lock()
以非阻塞的方式尝试获得锁。
与 std::mutex
不同的是,std::recursive_mutex
允许线程拥有当前互斥锁的期限内,可以重复进行尝试加锁(调用 lock()
或 try_lock()
函数)。需要注意的是,线程 需要进行对应数量次数的解锁(调用 unlock()
)才可以完全释放当前互斥量的锁。
std::recursive_mutex
提供了可以重复加锁的机制,通常也可以称之为 递归锁。
由于提供了重复(递归)加锁的特性,std::recursive_mutex
的效率是比较低的。当使用了递归锁时,我们通常要考虑代码是否还有优化空间,尽量避免使用递归锁。递归次数通常有限制(爆栈),但在 C++ 中一般较少出现此情况。
2 std::mutex 重复加锁出错
我们如果采用普通的 std::mutex
,进行重复尝试加锁,一般会出现死锁的状况,出现未定义行为。
1 |
|
在上面的代码中,写了一个递归函数 dfs()
,实现了嵌套的重复尝试加锁。创建了 3
个线程,每个线程递归 5
层,递归的每一层需要先进行加锁,然后对共享数据 count
进行 +1
,并输出数据的值。递归的每一层结束进行解锁。直到 k
为 0
时退出递归。
在 Windows 系统中运行可能的结果如下:
在 Windows 系统中,系统可能会通过采取一些优化策略、线程调度等,看似正确运行起来了,但实际上代码还是错误的。
在 Linux 系统中运行可能的结果如下:
在 Linux 系统中,显然程序运行不动了,表明出现了死锁。
3 std::recursive_mutex 实现重复加锁
我们可以将 std::mutex 重复加锁出错 代码中的 std::mutex
全部换成 std::recursive_mutex
即可。修改后就可以使得线程对一个互斥量进行重复加锁。
1 |
|
可能的运行结果如下: