在多线程编程中,锁是保证数据同步与线程安全的核心机制。但当一个线程多次获取同一把锁时,普通互斥锁会导致死锁。递归锁(Recursive Mutex)允许同一个线程多次获取同一把锁而不会产生死锁。本文将深入探讨 C++ 中递归锁的原理、使用场景及注意事项。
1. 锁的用法
C++11 标准库提供了std::recursive_mutex作为递归锁的实现,其使用方式与普通互斥锁类似,主要接口包括:
lock():获取锁(同一线程可多次调用)unlock():释放锁(需与 lock 次数匹配)try_lock():尝试获取锁(成功返回 true,失败返回 false)
#include <iostream>
#include <mutex>
#include <thread>
std::recursive_mutex mtx;
void demo()
{
// 递归锁允许获得锁的线程多次调用 lock 函数
mtx.lock();
mtx.lock();
// 调用多少次 lock,就需要调用几次 unlock,否则会发生死锁
mtx.unlock();
mtx.unlock();
if (mtx.try_lock())
{
std::cout << "count: " << mtx._Mtx_storage._Count << std::endl;
mtx.unlock();
std::cout << "count: " << mtx._Mtx_storage._Count << std::endl;
}
}
int main()
{
demo();
return 0;
}
2. 锁的原理
std::mutex 和 std::recursive_mutex 两个锁都是继承基类锁基类 _Mutex_base,但是传递给父类的锁类型参数不同:
class recursive_mutex : public _Mutex_base {
public:
recursive_mutex() noexcept
: _Mutex_base(_Mtx_recursive) {}
bool try_lock() noexcept {
return _Mutex_base::try_lock() && _Verify_ownership_levels();
}
recursive_mutex(const recursive_mutex&) = delete;
recursive_mutex& operator=(const recursive_mutex&) = delete;
};
递归锁在内部维护一个计数变量 _Count。当线程第一次获取锁时, _Count 被设置为 1,其他线程此时会被阻塞。如果同一线程再次对该锁加锁, _Count 会递增,表示该线程多次持有该锁。每次解锁 unlock 操作会使 _Count 递减,当 _Count 归零时,锁才会被真正释放,此时其他等待的线程才能继续获取该锁。
注意:下面代码运行需要把 recursive_mutex 的成员修改为 public 权限
#include <iostream>
#include <mutex>
#include <thread>
std::recursive_mutex mtx;
void print_count()
{
std::cout << "count: " << mtx._Mtx_storage._Count
<< " thread ID: " << mtx._Mtx_storage._Thread_id << std::endl;
}
void demo()
{
mtx.lock();
print_count();
mtx.lock();
print_count();
mtx.unlock();
print_count();
mtx.unlock();
print_count();
if (mtx.try_lock())
{
print_count();
mtx.unlock();
print_count();
}
}
int main()
{
demo();
return 0;
}
count: 1 thread ID: 6156 count: 2 thread ID: 6156 count: 1 thread ID: 6156 count: 0 thread ID: -1 count: 1 thread ID: 6156 count: 0 thread ID: -1

冀公网安备13050302001966号