互斥量概念,用法,死锁演示及解决详解

保护共享数据,用代码把共享数据锁住,其他想操作共享数据的线程得等待解锁。
互斥量的概念:
互斥量是个类对象。多个线程尝试lock锁上。结果:只有一个线程能够锁定成功,成功的标志是lock函数返回。如果没锁成功,那么流程就会卡在lock这,不断尝试去锁,一直到成功。
互斥量使用起来要小心,保护数据不要多也不要少,少了程序该崩溃还是崩溃,多了影响程序的运行效率。
互斥量的用法:
头文件

#include<mutex>//互斥量

步骤:先lock(),操作共享数据,unlock();
lock()和unlock()要成对使用。

static int num_push = 0;
static int num_pop = 0;
class A {
	std::list<int>msgReceive;
	std::mutex my_mutex;//创建一个互斥量的成员变量
public:
	void inMsgRecQueue()
	{
		for (int i = 0; i < 100; ++i)
		{
			cout << ++num_push << endl;
			my_mutex.lock();
			msgReceive.push_back(i);
			my_mutex.unlock();
		}
	}
	bool booloutMsg(int &commend)
	{
		my_mutex.lock();
		if (!msgReceive.empty())
		{
			cout << ++num_pop << endl;
			//消息不为空
			int commend = msgReceive.front();
			msgReceive.pop_front();

			my_mutex.unlock();
			//...其他处理
			return true;
		}
		cout << ++num_pop << endl;
		my_mutex.unlock();
		return false;
	}
	void outMsgRecQuene()
	{
		int commend = 0;
		for (int i = 0; i < 100; ++i)
		{
			bool result = booloutMsg(commend);
			if (result==true)
			{
				//成功处理
			}
			else
			{
				//消息为空
				cout << "outMsgRecQuene执行,但是消息队列为空!" << endl;
			}
		}
	}
};

int main()
{
	A a;
	std::thread myOutMsg(&A::outMsgRecQuene, &a);
	std::thread myRecMsg(&A::inMsgRecQueue, &a);

	myOutMsg.join();
	myRecMsg.join();

	cout << "num_push = " << num_push << endl
		<< "num_pop = " << num_pop << endl;
    return 0;
}
std::lock_guard<mutex> text<my_mutex>
构造函数里执行了mutex的lock(),析构函数里执行了mutex的unlock()。
但是不太灵活,必须要等析构函数执行才会解锁。

lock_guard实例

static int num_push = 0;
static int num_pop = 0;
class A {
	std::list<int>msgReceive;
	std::mutex my_mutex;//创建一个互斥量的成员变量
public:
	void inMsgRecQueue()
	{
		for (int i = 0; i < 100; ++i)
		{
			cout << ++num_push << endl;
			std::lock_guard<mutex> test_lock(my_mutex);
			msgReceive.push_back(i);
		}
	}
	bool booloutMsg(int &commend)
	{
		std::lock_guard<mutex> test_lock(my_mutex);
		if (!msgReceive.empty())
		{
			cout << ++num_pop << endl;
			//消息不为空
			int commend = msgReceive.front();
			msgReceive.pop_front();
			//...其他处理
			return true;
		}
		cout << ++num_pop << endl;
		return false;
	}
	void outMsgRecQuene()
	{
		int commend = 0;
		for (int i = 0; i < 100; ++i)
		{
			bool result = booloutMsg(commend);
			if (result==true)
			{
				//成功处理
			}
			else
			{
				//消息为空
				cout << "outMsgRecQuene执行,但是消息队列为空!" << endl;
			}
		}
	}
};

int main()
{
	A a;
	std::thread myOutMsg(&A::outMsgRecQuene, &a);
	std::thread myRecMsg(&A::inMsgRecQueue, &a);

	myOutMsg.join();
	myRecMsg.join();

	cout << "num_push = " << num_push << endl
		<< "num_pop = " << num_pop << endl;
    return 0;
}

死锁
产生的前提条件:是由至少两个互斥量才会产生这个问题。

static int num_push = 0;
static int num_pop = 0;
class A {
	std::list<int>msgReceive;
	std::mutex my_mutex1,my_mutex2;//创建一个互斥量的成员变量
public:
	void inMsgRecQueue()
	{
		for (int i = 0; i < 100; ++i)
		{
			cout << ++num_push << endl;
			my_mutex1.lock();
			my_mutex2.lock();
			msgReceive.push_back(i);
			my_mutex2.unlock();
			my_mutex1.unlock();
		}
	}
	bool booloutMsg(int &commend)
	{
		my_mutex2.lock();
		my_mutex1.lock();
		if (!msgReceive.empty())
		{
			cout << ++num_pop << endl;
			//消息不为空
			int commend = msgReceive.front();
			msgReceive.pop_front();
			//...其他处理
			my_mutex2.unlock();
			my_mutex1.unlock();
			return true;
		}
		my_mutex2.unlock();
		my_mutex1.unlock();
		cout << ++num_pop << endl;
		return false;
	}
	void outMsgRecQuene()
	{
		int commend = 0;
		for (int i = 0; i < 100; ++i)
		{
			bool result = booloutMsg(commend);
			if (result==true)
			{
				//成功处理
			}
			else
			{
				//消息为空
				cout << "outMsgRecQuene执行,但是消息队列为空!" << endl;
			}
		}
	}
};

int main()
{
	A a;
	std::thread myOutMsg(&A::outMsgRecQuene, &a);
	std::thread myRecMsg(&A::inMsgRecQueue, &a);

	myOutMsg.join();
	myRecMsg.join();

	cout << "num_push = " << num_push << endl
		<< "num_pop = " << num_pop << endl;
    return 0;
}

在这里插入图片描述

一般解决方案:只要顺序不搞乱,就不会出现死锁。
std::lock()函数模板:两个互斥量的时候才使用
要么两个互斥量都锁住,要么两个互斥量都没锁住。

static int num_push = 0;
static int num_pop = 0;
class A {
	std::list<int>msgReceive;
	std::mutex my_mutex1,my_mutex2;//创建一个互斥量的成员变量
public:
	void inMsgRecQueue()
	{
		for (int i = 0; i < 100; ++i)
		{
			cout << ++num_push << endl;
			std::lock(my_mutex1, my_mutex2);
			msgReceive.push_back(i);
			my_mutex2.unlock();
			my_mutex1.unlock();
		}
	}
	bool booloutMsg(int &commend)
	{
		std::lock(my_mutex1, my_mutex2);
		if (!msgReceive.empty())
		{
			cout << ++num_pop << endl;
			//消息不为空
			int commend = msgReceive.front();
			msgReceive.pop_front();
			//...其他处理
			my_mutex2.unlock();
			my_mutex1.unlock();
			return true;
		}
		my_mutex2.unlock();
		my_mutex1.unlock();
		cout << ++num_pop << endl;
		return false;
	}
	void outMsgRecQuene()
	{
		int commend = 0;
		for (int i = 0; i < 100; ++i)
		{
			bool result = booloutMsg(commend);
			if (result==true)
			{
				//成功处理
			}
			else
			{
				//消息为空
				cout << "outMsgRecQuene执行,但是消息队列为空!" << endl;
			}
		}
	}
};

int main()
{
	A a;
	std::thread myOutMsg(&A::outMsgRecQuene, &a);
	std::thread myRecMsg(&A::inMsgRecQueue, &a);

	myOutMsg.join();
	myRecMsg.join();

	cout << "num_push = " << num_push << endl
		<< "num_pop = " << num_pop << endl;
    return 0;
}

std::lock_guard<mutex> test(my_mutex1, std::adopt_lock);
表示之前已经锁过了。

static int num_push = 0;
static int num_pop = 0;
class A {
	std::list<int>msgReceive;
	std::mutex my_mutex1,my_mutex2;//创建一个互斥量的成员变量
public:
	void inMsgRecQueue()
	{
		for (int i = 0; i < 100; ++i)
		{
			cout << ++num_push << endl;
			std::lock(my_mutex1, my_mutex2);
			std::lock_guard<mutex> test(my_mutex1, std::adopt_lock);
			std::lock_guard<mutex> test1(my_mutex2, std::adopt_lock);
			msgReceive.push_back(i);
		}
	}
	bool booloutMsg(int &commend)
	{
		std::lock(my_mutex1, my_mutex2);
		std::lock_guard<mutex> test(my_mutex1, std::adopt_lock);
		std::lock_guard<mutex> test1(my_mutex2, std::adopt_lock);
		if (!msgReceive.empty())
		{
			cout << ++num_pop << endl;
			//消息不为空
			int commend = msgReceive.front();
			msgReceive.pop_front();
			//...其他处理
			return true;
		}
		cout << ++num_pop << endl;
		return false;
	}
	void outMsgRecQuene()
	{
		int commend = 0;
		for (int i = 0; i < 100; ++i)
		{
			bool result = booloutMsg(commend);
			if (result==true)
			{
				//成功处理
			}
			else
			{
				//消息为空
				cout << "outMsgRecQuene执行,但是消息队列为空!" << endl;
			}
		}
	}
};

int main()
{
	A a;
	std::thread myOutMsg(&A::outMsgRecQuene, &a);
	std::thread myRecMsg(&A::inMsgRecQueue, &a);

	myOutMsg.join();
	myRecMsg.join();

	cout << "num_push = " << num_push << endl
		<< "num_pop = " << num_pop << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/a12345d132/article/details/84484908