C++11的多线程并发编程(四)

C++11的多线程并发编程(四)

—互斥量和死锁

  1. 互斥量 mutex
    互斥量是一个类对象,作用是要是对要读写的数据进行加锁,通过调用lock()函数表示目前只有这个进程可以进行共享数据的操作,别的进程只有等待,当这个进程调用unlock函数的时候,表示解锁。
    针对上一次案例,进行加锁和解锁操作,,lock和unlock是成双出现的,不可能你占用了一个锁,执行结束还占着,这样其他进程就无法获得锁。
#include <iostream>
#include <thread>
#include <list>
#include <mutex>

using namespace std;

class A
{
public:
	void inCommand()
	{
		for(int i = 0; i < 1000; i++)
		{
			mylock.lock();
			ticket.push_back(i);
			cout << "a command is comming" << endl;
			mylock.unlock();
		}
	}
	
	void outCommand()
	{
		for(int j = 0; j < 1000; j++)
		{
			mylock.lock();
			if(!ticket.empty())
			{
				int command = ticket.front();
				ticket.pop_front();	
				cout << "command is :" << command << endl;
				mylock.unlock();
			}
			else
			{
				cout << "there is no people" << endl;	
				mylock.unlock();
			}
		}
		
	}
	
private:
	list<int> ticket;
	mutex mylock;
};

int main(int argc, char *argv[])
{
	A a;
	thread thread1(&A::inCommand, &a);
	thread thread2(&A::outCommand, &a);
	thread1.join();
	thread2.join();

	cout << "the main thread is end;" << endl;
	return 0;
}

这样就可以稳定运行起来了。

  1. lock_guard
    上面的例子,会发现当程序运行中出现了一个问题,然后排查半天是因为,有个线程加锁,但是忘记写unlock()函数,因此c++提供了一个类模板lock_guard该功能就类似于智能指针解决忘记清除内存的问题一样,lock_guard提供构造函数,以及析构函数,构造函数就是加锁,析构函数就是解锁。,当创建的类对象超过了所在的作用域就会进行析构函数调用。
    因此进行修改:
#include <iostream>
#include <thread>
#include <list>
#include <mutex>

using namespace std;

class A
{
public:
	void inCommand()
	{
		for(int i = 0; i < 1000; i++)
		{
			lock_guard<mutex> myguard(mylock);
		//	mylock.lock();
			ticket.push_back(i);
			cout << "a command is comming" << endl;
		//	mylock.unlock();
		}
	}
	
	void outCommand()
	{
		for(int j = 0; j < 1000; j++)
		{
			lock_guard<mutex> myguard(mylock);
		//	mylock.lock();
			if(!ticket.empty())
			{
				int command = ticket.front();
				ticket.pop_front();	
				cout << "command is :" << command << endl;
			//	mylock.unlock();
			}
			else
			{
				cout << "there is no people" << endl;	
			//	mylock.unlock();
			}
		}
		
	}
	
private:
	list<int> ticket;
	mutex mylock;
};

int main(int argc, char *argv[])
{
	A a;
	thread thread1(&A::inCommand, &a);
	thread thread2(&A::outCommand, &a);
	thread1.join();
	thread2.join();

	cout << "the main thread is end;" << endl;
	return 0;
}

可以观察到,运行结果与上一个例子相同,没有异常。

  1. 死锁
    死锁出现的条件是两个线程都要运行,但两个线程都在等对方解锁,也就是,线程1加锁A,申请加锁B,而线程2加锁B,申请加锁A,这样线程12都没法继续执行下去。
    那么在代码中就会看见这样情况:
mutex mymutex1;
mutex mymutex2;

thread1:
	mymutex1.lock();
	mymutex2.lock();
	.....
	mymutex1.unlock();
	mymutex2.unlock();

thread2:
	mymutex2.lock();
	mymutex1.lock();
	....
	mymutex2.unlock();
	mymutex1.unlock();

两个线程都执行完第一句,一个等着另一个,互相等着的,这样就是死锁。

  1. 解决办法
    lock()与adopt_lock的作用,lock()函数参数就是mutex,有多少个锁就多少个参数,它表示,要么一起申请了,要么一起不要了,这样就不会造成一个死锁的状态,然后,在不需要的时候对每一个锁进行unlock()。还有一种办法就是,adopt_lock,是一个参数放在lock_guard中,
    他表示lock_guard不执行构造函数,直接生命周期结束后直接析构函数。
    看例子就明白了:
#include <iostream>
#include <thread>
#include <list>
#include <mutex>

using namespace std;

class A
{
public:
	void inCommand()
	{
		for(int i = 0; i < 1000; i++)
		{
			lock(mylock1,mylock2);
			lock_guard<mutex> myguard1(mylock1,adopt_lock);
			lock_guard<mutex> myguard2(mylock2,adopt_lock);
		//	mylock.lock();
			ticket.push_back(i);
			cout << "a command is comming" << endl;
		//	mylock.unlock();
		}
	}
	
	void outCommand()
	{
		for(int j = 0; j < 1000; j++)
		{
			lock(mylock1,mylock2);
			lock_guard<mutex> myguard1(mylock1,adopt_lock);
			lock_guard<mutex> myguard2(mylock2,adopt_lock);
			//	mylock.lock();
			if(!ticket.empty())
			{
				int command = ticket.front();
				ticket.pop_front();	
				cout << "command is :" << command << endl;
			//	mylock.unlock();
			}
			else
			{
				cout << "there is no people" << endl;	
			//	mylock.unlock();
			}
		}
		
	}
	
private:
	list<int> ticket;
	mutex mylock1;
	mutex mylock2;
};

int main(int argc, char *argv[])
{
	A a;
	thread thread1(&A::inCommand, &a);
	thread thread2(&A::outCommand, &a);
	thread1.join();
	thread2.join();

	cout << "the main thread is end;" << endl;
	return 0;
}

结果还是稳定执行,无异常。
在这里插入图片描述
疫情依旧很严重,小区都已经封了,望早日结束早日开学。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值