1、递归锁
允许同一个线程多次加锁而不死锁,不同线程加锁和正常的互斥量一样。
2、应用场景
解决这后续描述的一类问题。在一个函数内给互斥量上了锁还没有解开,然后又调用了另一个函数,这个被调用的函数也去给互斥量上锁,这种情境下就会出现死锁。
3、递归互斥量
主要是通过对同一个线程的加锁请求计数。
4、实现CRecursiveMutex主要包含的变量
mutex m_recursive_mutex; // 用于不同线程加锁的互斥量
map<std::thread::id, int> map_thread_lock_nums; // 统计不同线程lock()的次数
mutex m_map_mutex; // 用于保护map_thread_lock_nums
#ifndef _RECURSIVELOCK_H_
#define _RECURSIVELOCK_H_
#include <map>
#include <mutex>
#include <thread>
#include <chrono>
#include <iostream>
#include <condition_variable>
using namespace std;
// 递归锁:允许同一个线程多次加锁而不死锁,不同线程加锁和正常的互斥量一样
// 应用场景:解决这类问题,在一个函数内给互斥量上了锁还没有解开,然后又调用了另一个函数,这个被调用的函数也去给互斥量上锁,这种情境下就会出现死锁。
// 递归互斥量:主要是通过对同一个线程的加锁请求计数
class CRecursiveMutex
{
public:
CRecursiveMutex()
{
map_thread_lock_nums.clear();
}
~CRecursiveMutex()
{}
void Lock()
{
m_map_mutex.lock();
// 当前线程未获取过recursive_mutex
if (map_thread_lock_nums.find(this_thread::get_id()) == map_thread_lock_nums.end() || map_thread_lock_nums[this_thread::get_id()] == 0)
{
map_thread_lock_nums[this_thread::get_id()] = 1;
m_map_mutex.unlock(); // 这里一定要先释放m_map_mutex锁,否则m_recursive_mutex.lock()在前面的话,会出现死锁
m_recursive_mutex.lock();
}
else // 当前线程曾经获取过recursive_mutex,增加加锁次数
{
map_thread_lock_nums[this_thread::get_id()] += 1;
m_map_mutex.unlock();
}
}
void Unlock()
{
m_map_mutex.lock();
if (map_thread_lock_nums.find(this_thread::get_id()) == map_thread_lock_nums.end() || map_thread_lock_nums[this_thread::get_id()] == 0)
{
m_map_mutex.unlock();
cout << "CRecursiveMutex Lock和Unlock未成对使用!\n"; // 进入到这里说明 CRecursiveMutex Lock和Unlock未成对使用
}
else
{
if (map_thread_lock_nums[this_thread::get_id()] == 1) // 当前线程最后一次调用Unlock,需要解锁
{
map_thread_lock_nums.erase(this_thread::get_id());
m_recursive_mutex.unlock();
}
else
{
map_thread_lock_nums[this_thread::get_id()] -= 1; // 当前线程不是最后一次调用Unlock,计数减1
}
m_map_mutex.unlock();
}
}
private:
mutex m_recursive_mutex; // 用于不同线程加锁的互斥量
map<std::thread::id, int> map_thread_lock_nums; // 统计不同线程m_recursive_mutex.lock()的次数
mutex m_map_mutex; // 用于保护map_thread_lock_nums
};
// 托管递归互斥量的类型
class CRecursiveMutexLock
{
public:
explicit CRecursiveMutexLock(CRecursiveMutex& rwmutex)
: m_recursive_mutex(rwmutex)
{
m_recursive_mutex.Lock();
}
virtual ~CRecursiveMutexLock()
{
m_recursive_mutex.Unlock();
}
private:
CRecursiveMutexLock() = delete;
CRecursiveMutexLock(const CRecursiveMutexLock&) = delete;
CRecursiveMutexLock& operator=(const CRecursiveMutexLock&) = delete;
private:
CRecursiveMutex& m_recursive_mutex;
};
// 测试使用
int g_num = 0; // 为 g_num_mutex 所保护
CRecursiveMutex g_recursive_mutex_; // 递归锁互斥量
// 测试自己写的递归锁
void RecursiveMutexProc(int id)
{
for (int i = 0; i < 10; ++i)
{
// 同一线程里多次加锁,不会死锁
CRecursiveMutexLock m_recursive_mutex1(g_recursive_mutex_);
CRecursiveMutexLock m_recursive_mutex2(g_recursive_mutex_);
CRecursiveMutexLock m_recursive_mutex3(g_recursive_mutex_);
++g_num;
std::cout << id << " => " << g_num << '\n';
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
// 测试自己实现的CRecursiveMutex
void Test_RecursiveMutexPrco()
{
g_num = 0;
cout << "自写CRecursiveMutex" << endl;
std::thread t1(RecursiveMutexProc, 1);
std::thread t2(RecursiveMutexProc, 2);
std::thread t3(RecursiveMutexProc, 3);
std::thread t4(RecursiveMutexProc, 4);
t1.join();
t2.join();
t3.join();
t4.join();
}
#endif //_RECURSIVELOCK_H_