C++实现递归锁CRecursiveMutex

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_

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值