互斥量基本概念

一、互斥量(mutex)的基本概念

  • 互斥量就是个类对象,可以理解为一把锁,多个线程尝试用lock()成员函数来加锁,只有一个线程能锁定成功,如果没有锁成功,那么流程将卡在lock()这里不断尝试去锁定。
  • 互斥量使用要小心,保护数据不多也不少,少了达不到效果,多了影响效率。

二、互斥量的用法

2.1 lock(),unlock()

  • 添加头文件:#include<mutex>
  • 声明与创建:std::mutex my_mutex;
  • lock()—>操作共享数据—>unlock()(这类错误很难排查)

lock()unlock()务必要成对使用

//函数void inMsgRecvQueue()加锁片段:
	my_mutex.lock();
	msgRecvQueue.push_back(i);
	my_mutex.unlock();
	
//函数outMsgLULProc(int& command)加锁片段:
	my_mutex.lock();
	if (!msgRecvQueue.empty())
	{
		//命令队列不为空
		int command = msgRecvQueue.front();//得到第一条命令
		msgRecvQueue.pop_front();//移除刚取出命令
		my_mutex.unlock();//每一个分支出口处都需要解锁unlock()
		return true;
	}
	my_mutex.unlock();//每一个分支出口处都需要解锁unlock()
	return false;

2.2 std::lock_guard()
直接取代lock()和unlock(),使用std::lock_guard()后不能再使用lock()unlock()

luck_guard()原理: lock_guard()是类模板,当在函数中创建局部类模板实例的时候,在构造函数中执行lock(),当函数运行结束后,在在析构函数中执行unlock()。

使用lock_guard()替换:

	//函数void inMsgRecvQueue()加锁片段:
		std::lock_guard<std::mutex>myLockGuard(my_mutex);
		//my_mutex.lock();
		msgRecvQueue.push_back(i);
		//my_mutex.unlock();

	//函数outMsgLULProc(int& command)加锁片段:
		std::lock_guard<std::mutex>myLockGuard(my_mutex);
		//my_mutex.lock();
		if (!msgRecvQueue.empty())
		{
			//命令队列不为空
			int command = msgRecvQueue.front();//得到第一条命令
			msgRecvQueue.pop_front();//移除刚取出命令
			//my_mutex.unlock();
			return true;
		}
		//my_mutex.unlock();
		return false;

三、死锁
一个互斥量(mutex)即为一把锁,死锁由至少两个互斥量产生。

3.1 死锁演示:

//函数void inMsgRecvQueue()加锁片段:
	my_mutex1.lock();
	my_mutex2.lock();
	msgRecvQueue.push_back(i);
	my_mutex2.unlock();
	my_mutex1.lock();
	
//函数outMsgLULProc(int& command)加锁片段:
	my_mutex2.lock();
	my_mutex1.lock();
	if (!msgRecvQueue.empty())
	{
		//命令队列不为空
		int command = msgRecvQueue.front();//得到第一条命令
		msgRecvQueue.pop_front();//移除刚取出命令
		my_mutex1.lock();
		my_mutex2.lock();
		return true;
	}
	my_mutex1.lock();
	my_mutex2.lock();
	return false;

3.2 死锁一般解决方案:

  • 多个锁lock()顺序一致

3.3 std::lock()函数模板: 一次可锁住至少一个互斥量。(不存在多个锁出现死锁状况)谨慎使用

要么都锁,要么都不锁,只要有一个锁不住就都马上解锁,防止死锁产生。
使用方式: std::lock(my_mutex1,my_mutex2);

3.4 使用std::lock()配合lock_guard()防止忘记解锁:

	std::lock(my_mutex1, my_mutex2);
	std::lock_guard<std::mutex> my_lock_guard(my_mutex1, std::adopt_lock);
	std::lock_guard<std::mutex> my_lock_guard(my_mutex2, std::adopt_lock);
	msgRecvQueue.push_back(i);

std::adopt_lock表示该锁已经锁上,不需要在lock_guard()再次上锁。

更多内容欢迎参见我的个人网站:http://www.huazhige.online/


版权声明:本文为weixin_45983489原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。