博客
关于我
C++ 并发与多线程(五)
阅读量:339 次
发布时间:2019-03-04

本文共 46814 字,大约阅读时间需要 156 分钟。

unique_lock详解

1.unique_lock取代lock_guard

// 并发与多线程2_4.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//#include "pch.h"#include <iostream>#include <vector>#include <thread>#include <list>#include  <mutex>using namespace std;//vector<int>g_v = { 1,2,3 };////void Myprint(int inum)//{   //	cout << "myprint线程开始执行了,线程编号" << inum << endl;//	cout << "myprint线程结束执行了,线程编号" << inum << endl;//	cout << "id 为" << std::this_thread::get_id() << "打印g_v值" << g_v[0] << g_v[1] << g_v[2] << endl;////}class A{   public:	//把玩家命令放入到一个队列的进程	void inMsgRecvQueue()	{   		for (int i = 0; i < 100000; i++)		{   			//my_mutex.lock();			cout << "inMsgRecvQueue执行,插入一个元素" << i << endl;			{   				//my_mutex1.lock();		//先锁金锁 实际中两个lock间会执行其他的东西				//my_mutex2.lock();		//再锁银锁				//使用std::lock()				//std::lock(my_mutex1, my_mutex2);    //相当与每个互斥量都调用了lock				//std::lock_guard<mutex>sbguard1(my_mutex1, adopt_lock);				//std::lock_guard<mutex>sbguard2(my_mutex2, adopt_lock);				std::unique_lock<std::mutex>sbguard1(my_mutex1);				msgRecvQueue.push_back(i);     //假设数字i为命令 放入队列					//my_mutex2.unlock();				//顺序无所谓				//my_mutex1.unlock();			}		}	}	bool outMsgLULproc(int &command)	{   		//lock_guard<mutex>sbguard(my_mutex1);       //sbguard是对象名		//my_mutex1.lock();		//my_mutex2.lock();		//std::lock(my_mutex1, my_mutex2);		std::unique_lock<std::mutex>sbguard1(my_mutex1);		if (!msgRecvQueue.empty())		{   		    command = msgRecvQueue.front();      //返回第一个元素但不检查元素是否存在			msgRecvQueue.pop_front();            //移除第一个元素但不返回			//处理数据。。。。。			/*my_mutex1.unlock();			my_mutex2.unlock();*/			return true;		}			else		{   			//my_mutex1.unlock();			//my_mutex2.unlock();			return false; 		}		}	//读取命令的线程	void outMsgRecvQueue()	{   		int command = 0;			for (int i = 0; i < 100000; i++)		{   			bool result = outMsgLULproc(command);			if (result == true)			{   							cout << "outMsgRecvQueue 执行,取出一个元素" << command << endl;				//数据处理			}				}		cout << "end" << endl;		}private:	std::list<int>msgRecvQueue;	mutex my_mutex1;           //创建一个互斥量	mutex my_mutex2;     };int main(){    //   //一 创建线程和等待多个线程	//vector<thread>mythreads;	创建10个线程,线程入口函数统一使用 myprint	1)多线程执行顺序是乱的	2)这种join写法更容易写出稳定程序	3)把thread对象放入到容器里,对管理大量线程有帮助	//for (int i = 0; i < 10; i++)	//{   	//	//创建10个线程,已经开始执行	//	mythreads.push_back(thread(Myprint, i));	//	//}	//for (auto iter = mythreads.begin(); iter != mythreads.end(); ++iter)	//{   	//	iter->join();	//}	//cout << "I LOVE CHINA" << endl;	//二 数据共享	//2.1只读数据	//2.2 有读有写	//最简单的不崩溃处理 读和写不能同时进行	//2.3其他案例	//数据共享:    		//三 共享数据的保护案例代码	//网络游戏服务器,有两个自己创建的线程,一个线程手机玩家命令(数字表示),并把名利数据写入到一个队列中。	//另一个线程从队列中取出玩家发送来的命令,解析,然后执行玩家的动作。	//使用list,频繁的按顺序插入和删除时效率较高	//用成员函数作为线程函数的方法写线程	A myobja;	thread myOutnMsg(&A::outMsgRecvQueue, &myobja);	thread myInMsgObj(&A::inMsgRecvQueue, &myobja);	myOutnMsg.join();	myInMsgObj.join();	//四 互斥量的概念	//步骤:先lock 操作共享数据 然后unlock	//lock和unlock要成对使用。有lock忘记unlock的问题非常难排查	//为了防止忘记unlock(),引入了一个叫std::lock_guard的类模板	//智能指针(unique_ptr<>)	//std::lock_guard类模板 直接取代lock()和unlock(),用了类模板不能再用lock和unlock	//要将保护量放在lock和unlock里	//五 死锁	/*	**死锁问题的前提条件是:有至少两个锁,即至少两个互斥量,金锁(Jinlock),银锁(Yinlock)**	两个线程A,B	线程A执行时,先锁金锁,然后去锁银锁	两个线程出现了上下文切换,线程B执行了,线程B先锁银锁,因为银锁没有被A锁上,所以被B锁上了,然后线程B去锁金锁	此时产生了死锁	线程A锁不了银锁,流程走不下去	线程B锁不了金锁,流程走不下去	死锁产生的关键是两个互斥量的上锁顺序不一致	*/	//5.1死锁演示	//5.2死锁的一般解决方案	//只要保证两个互斥量上锁的顺序一致,就不会造成死锁。	//5.3 std::lock()函数模板	//能力:一次锁住两个或者两个以上的互斥量(至少两个,多了不限,一个不行)	//不存在因为锁头的顺序问题导致出现死锁问题。	//如果互斥量中有一个没锁住,则等待,等待所有互斥量否锁住,才能继续往下走	//特点:要么两个互斥量都锁住,要么两个互斥量都没锁住。如果只锁了一个,另外一个没成功,则立即解锁已经锁住的。	//用来处理多个互斥量的情况	//5.4 std:lock_guard的std:adopt_lock参数	//六 unique_lock取代lock_guard	//unique_lock是个类模板,工作中推荐使用lock_guard	//lock_guard取代了mutex的lock和unlock	//unique_lock比lock_guard灵活,效率略差,内存占用稍多。}

在这里插入图片描述

2.unique_lock的第二个参数

2.1 adopt_lock

// 并发与多线程2_4.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//#include "pch.h"#include <iostream>#include <vector>#include <thread>#include <list>#include  <mutex>using namespace std;//vector<int>g_v = { 1,2,3 };////void Myprint(int inum)//{   //	cout << "myprint线程开始执行了,线程编号" << inum << endl;//	cout << "myprint线程结束执行了,线程编号" << inum << endl;//	cout << "id 为" << std::this_thread::get_id() << "打印g_v值" << g_v[0] << g_v[1] << g_v[2] << endl;////}class A{   public:	//把玩家命令放入到一个队列的进程	void inMsgRecvQueue()	{   		for (int i = 0; i < 100000; i++)		{   			//my_mutex.lock();			cout << "inMsgRecvQueue执行,插入一个元素" << i << endl;			{   				//my_mutex1.lock();		//先锁金锁 实际中两个lock间会执行其他的东西				//my_mutex2.lock();		//再锁银锁				//使用std::lock()				//std::lock(my_mutex1, my_mutex2);    //相当与每个互斥量都调用了lock				//std::lock_guard<mutex>sbguard1(my_mutex1, adopt_lock);				//std::lock_guard<mutex>sbguard2(my_mutex2, adopt_lock);				//std::unique_lock<std::mutex>sbguard1(my_mutex1);				my_mutex1.lock();                     //in线程后到				std::unique_lock<std::mutex>sbguard1(my_mutex1,adopt_lock);  //使用了adopt_lock 需要提前lock				msgRecvQueue.push_back(i);     //假设数字i为命令 放入队列					//my_mutex2.unlock();				//顺序无所谓				//my_mutex1.unlock();			}		}	}	bool outMsgLULproc(int &command)	{   		//lock_guard<mutex>sbguard(my_mutex1);       //sbguard是对象名		//my_mutex1.lock();		//my_mutex2.lock();		//std::lock(my_mutex1, my_mutex2);		std::chrono::milliseconds dura(20000);    //等待20s		std::this_thread::sleep_for(dura);		  //休息一定时长  outMsgLULproc先跑起来		std::unique_lock<std::mutex>sbguard1(my_mutex1);		if (!msgRecvQueue.empty())		{   		    command = msgRecvQueue.front();      //返回第一个元素但不检查元素是否存在			msgRecvQueue.pop_front();            //移除第一个元素但不返回			//处理数据。。。。。			/*my_mutex1.unlock();			my_mutex2.unlock();*/			return true;		}			else		{   			//my_mutex1.unlock();			//my_mutex2.unlock();			return false; 		}		}	//读取命令的线程	void outMsgRecvQueue()	{   		int command = 0;			for (int i = 0; i < 100000; i++)		{   			bool result = outMsgLULproc(command);			if (result == true)			{   							cout << "outMsgRecvQueue 执行,取出一个元素" << command << endl;				//数据处理			}				}		cout << "end" << endl;		}private:	std::list<int>msgRecvQueue;	mutex my_mutex1;           //创建一个互斥量	mutex my_mutex2;     };int main(){    //   //一 创建线程和等待多个线程	//vector<thread>mythreads;	创建10个线程,线程入口函数统一使用 myprint	1)多线程执行顺序是乱的	2)这种join写法更容易写出稳定程序	3)把thread对象放入到容器里,对管理大量线程有帮助	//for (int i = 0; i < 10; i++)	//{   	//	//创建10个线程,已经开始执行	//	mythreads.push_back(thread(Myprint, i));	//	//}	//for (auto iter = mythreads.begin(); iter != mythreads.end(); ++iter)	//{   	//	iter->join();	//}	//cout << "I LOVE CHINA" << endl;	//二 数据共享	//2.1只读数据	//2.2 有读有写	//最简单的不崩溃处理 读和写不能同时进行	//2.3其他案例	//数据共享:    		//三 共享数据的保护案例代码	//网络游戏服务器,有两个自己创建的线程,一个线程手机玩家命令(数字表示),并把名利数据写入到一个队列中。	//另一个线程从队列中取出玩家发送来的命令,解析,然后执行玩家的动作。	//使用list,频繁的按顺序插入和删除时效率较高	//用成员函数作为线程函数的方法写线程	A myobja;	thread myOutnMsg(&A::outMsgRecvQueue, &myobja);	thread myInMsgObj(&A::inMsgRecvQueue, &myobja);	myOutnMsg.join();	myInMsgObj.join();	//四 互斥量的概念	//步骤:先lock 操作共享数据 然后unlock	//lock和unlock要成对使用。有lock忘记unlock的问题非常难排查	//为了防止忘记unlock(),引入了一个叫std::lock_guard的类模板	//智能指针(unique_ptr<>)	//std::lock_guard类模板 直接取代lock()和unlock(),用了类模板不能再用lock和unlock	//要将保护量放在lock和unlock里	//五 死锁	/*	**死锁问题的前提条件是:有至少两个锁,即至少两个互斥量,金锁(Jinlock),银锁(Yinlock)**	两个线程A,B	线程A执行时,先锁金锁,然后去锁银锁	两个线程出现了上下文切换,线程B执行了,线程B先锁银锁,因为银锁没有被A锁上,所以被B锁上了,然后线程B去锁金锁	此时产生了死锁	线程A锁不了银锁,流程走不下去	线程B锁不了金锁,流程走不下去	死锁产生的关键是两个互斥量的上锁顺序不一致	*/	//5.1死锁演示	//5.2死锁的一般解决方案	//只要保证两个互斥量上锁的顺序一致,就不会造成死锁。	//5.3 std::lock()函数模板	//能力:一次锁住两个或者两个以上的互斥量(至少两个,多了不限,一个不行)	//不存在因为锁头的顺序问题导致出现死锁问题。	//如果互斥量中有一个没锁住,则等待,等待所有互斥量否锁住,才能继续往下走	//特点:要么两个互斥量都锁住,要么两个互斥量都没锁住。如果只锁了一个,另外一个没成功,则立即解锁已经锁住的。	//用来处理多个互斥量的情况	//5.4 std:lock_guard的std:adopt_lock参数	//六 unique_lock取代lock_guard	//unique_lock是个类模板,工作中推荐使用lock_guard	//lock_guard取代了mutex的lock和unlock	//unique_lock比lock_guard灵活,效率略差,内存占用稍多。	//七 unique_lock的第二个参数	//lock_guard中的adopt_lock起标记作用 表示互斥量已经被lock了,在写这个标记前需要把互斥量lock 否则报错	//adopt的效果是:假设调用方 线程已经拥有了互斥的所有权(已经lock成功了)	//unique_lock也有adopt_lock标记,含义相同。	//灵活性:	//对于同一个锁 如果其中一个线程上了锁,则另一个也需要这个锁的线程就会处于等待状态,知道前一个线程解锁,会浪费很多时间	//使用}

2.2 try_to_lock

尝试用mutex的lock()去锁定lock,但如果没有锁定成功,也会立即返回,并不会阻塞,用try_to_ lock的前提是不可以提前上锁,否则异常。

// 并发与多线程2_4.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//#include "pch.h"#include <iostream>#include <vector>#include <thread>#include <list>#include  <mutex>using namespace std;//vector<int>g_v = { 1,2,3 };////void Myprint(int inum)//{   //	cout << "myprint线程开始执行了,线程编号" << inum << endl;//	cout << "myprint线程结束执行了,线程编号" << inum << endl;//	cout << "id 为" << std::this_thread::get_id() << "打印g_v值" << g_v[0] << g_v[1] << g_v[2] << endl;////}class A{   public:	//把玩家命令放入到一个队列的进程	void inMsgRecvQueue()	{   		for (int i = 0; i < 100000; i++)		{   			//my_mutex.lock();						{   				//my_mutex1.lock();		//先锁金锁 实际中两个lock间会执行其他的东西				//my_mutex2.lock();		//再锁银锁				//使用std::lock()				//std::lock(my_mutex1, my_mutex2);    //相当与每个互斥量都调用了lock				//std::lock_guard<mutex>sbguard1(my_mutex1, adopt_lock);				//std::lock_guard<mutex>sbguard2(my_mutex2, adopt_lock);				//std::unique_lock<std::mutex>sbguard1(my_mutex1);				//my_mutex1.lock();                     //in线程后到				//std::unique_lock<std::mutex>sbguard1(my_mutex1,adopt_lock);  //使用了adopt_lock 需要提前lock				//尝试加锁				std::unique_lock<std::mutex>sbguard1(my_mutex1, std::try_to_lock);         //使用此参数的条件时互斥量没有上锁				if (sbguard1.owns_lock())				{   					cout << "inMsgRecvQueue执行,插入一个元素" << i << endl;					msgRecvQueue.push_back(i);     //假设数字i为命令 放入队列				}				else				{   					cout << "inMsgRecvQueue 执行,但没有上锁。。。。" << endl;				}									//my_mutex2.unlock();				//顺序无所谓				//my_mutex1.unlock();			}		}	}	bool outMsgLULproc(int &command)	{   		//lock_guard<mutex>sbguard(my_mutex1);       //sbguard是对象名		//my_mutex1.lock();		//my_mutex2.lock();		//std::lock(my_mutex1, my_mutex2);			std::unique_lock<std::mutex>sbguard1(my_mutex1);		std::chrono::milliseconds dura(10);    //等待10ms		std::this_thread::sleep_for(dura);		  //休息一定时长  outMsgLULproc先跑起来		if (!msgRecvQueue.empty())		{   		    command = msgRecvQueue.front();      //返回第一个元素但不检查元素是否存在			msgRecvQueue.pop_front();            //移除第一个元素但不返回			//处理数据。。。。。			/*my_mutex1.unlock();			my_mutex2.unlock();*/			return true;		}			else		{   			//my_mutex1.unlock();			//my_mutex2.unlock();			return false; 		}		}	//读取命令的线程	void outMsgRecvQueue()	{   		int command = 0;			for (int i = 0; i < 100000; i++)		{   			bool result = outMsgLULproc(command);			if (result == true)			{   							cout << "outMsgRecvQueue 执行,取出一个元素" << command << endl;				//数据处理			}				}		cout << "end" << endl;		}private:	std::list<int>msgRecvQueue;	mutex my_mutex1;           //创建一个互斥量	mutex my_mutex2;     };int main(){    //   //一 创建线程和等待多个线程	//vector<thread>mythreads;	创建10个线程,线程入口函数统一使用 myprint	1)多线程执行顺序是乱的	2)这种join写法更容易写出稳定程序	3)把thread对象放入到容器里,对管理大量线程有帮助	//for (int i = 0; i < 10; i++)	//{   	//	//创建10个线程,已经开始执行	//	mythreads.push_back(thread(Myprint, i));	//	//}	//for (auto iter = mythreads.begin(); iter != mythreads.end(); ++iter)	//{   	//	iter->join();	//}	//cout << "I LOVE CHINA" << endl;	//二 数据共享	//2.1只读数据	//2.2 有读有写	//最简单的不崩溃处理 读和写不能同时进行	//2.3其他案例	//数据共享:    		//三 共享数据的保护案例代码	//网络游戏服务器,有两个自己创建的线程,一个线程手机玩家命令(数字表示),并把名利数据写入到一个队列中。	//另一个线程从队列中取出玩家发送来的命令,解析,然后执行玩家的动作。	//使用list,频繁的按顺序插入和删除时效率较高	//用成员函数作为线程函数的方法写线程	A myobja;	thread myOutnMsg(&A::outMsgRecvQueue, &myobja);	thread myInMsgObj(&A::inMsgRecvQueue, &myobja);	myOutnMsg.join();	myInMsgObj.join();	//四 互斥量的概念	//步骤:先lock 操作共享数据 然后unlock	//lock和unlock要成对使用。有lock忘记unlock的问题非常难排查	//为了防止忘记unlock(),引入了一个叫std::lock_guard的类模板	//智能指针(unique_ptr<>)	//std::lock_guard类模板 直接取代lock()和unlock(),用了类模板不能再用lock和unlock	//要将保护量放在lock和unlock里	//五 死锁	/*	**死锁问题的前提条件是:有至少两个锁,即至少两个互斥量,金锁(Jinlock),银锁(Yinlock)**	两个线程A,B	线程A执行时,先锁金锁,然后去锁银锁	两个线程出现了上下文切换,线程B执行了,线程B先锁银锁,因为银锁没有被A锁上,所以被B锁上了,然后线程B去锁金锁	此时产生了死锁	线程A锁不了银锁,流程走不下去	线程B锁不了金锁,流程走不下去	死锁产生的关键是两个互斥量的上锁顺序不一致	*/	//5.1死锁演示	//5.2死锁的一般解决方案	//只要保证两个互斥量上锁的顺序一致,就不会造成死锁。	//5.3 std::lock()函数模板	//能力:一次锁住两个或者两个以上的互斥量(至少两个,多了不限,一个不行)	//不存在因为锁头的顺序问题导致出现死锁问题。	//如果互斥量中有一个没锁住,则等待,等待所有互斥量否锁住,才能继续往下走	//特点:要么两个互斥量都锁住,要么两个互斥量都没锁住。如果只锁了一个,另外一个没成功,则立即解锁已经锁住的。	//用来处理多个互斥量的情况	//5.4 std:lock_guard的std:adopt_lock参数	//六 unique_lock取代lock_guard	//unique_lock是个类模板,工作中推荐使用lock_guard	//lock_guard取代了mutex的lock和unlock	//unique_lock比lock_guard灵活,效率略差,内存占用稍多。	//七 unique_lock的第二个参数	// 7.1 adopt_lock	//lock_guard中的adopt_lock起标记作用 表示互斥量已经被lock了,在写这个标记前需要把互斥量lock 否则报错	//adopt的效果是:假设调用方 线程已经拥有了互斥的所有权(已经lock成功了)	//unique_lock也有adopt_lock标记,含义相同。	//灵活性:	//对于同一个锁 如果其中一个线程上了锁,则另一个也需要这个锁的线程就会处于等待状态,知道前一个线程解锁,会浪费很多时间		//7.2 std::try to lock	//尝试用mutex的lock()去锁定lock,但如果没有锁定成功,也会立即返回,并不会阻塞	//用try to lock的前提是不可以手动上锁,否则异常}

当没有上锁成功时,try to lock可以通过判断条件进入自定义事件
在这里插入图片描述

2.3 std::defer_lock

初始化一个没有上锁的互斥量mutex

3.unique_lock的成员函数

3.1 lock() 加锁

通过调用unique_lock的成员函数lock,自动上锁和解锁,配合defer_lock使用。

// 并发与多线程2_4.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//#include "pch.h"#include <iostream>#include <vector>#include <thread>#include <list>#include  <mutex>using namespace std;//vector<int>g_v = { 1,2,3 };////void Myprint(int inum)//{   //	cout << "myprint线程开始执行了,线程编号" << inum << endl;//	cout << "myprint线程结束执行了,线程编号" << inum << endl;//	cout << "id 为" << std::this_thread::get_id() << "打印g_v值" << g_v[0] << g_v[1] << g_v[2] << endl;////}class A{   public:	//把玩家命令放入到一个队列的进程	void inMsgRecvQueue()	{   		for (int i = 0; i < 100000; i++)		{   			//my_mutex.lock();						{   				//my_mutex1.lock();		//先锁金锁 实际中两个lock间会执行其他的东西				//my_mutex2.lock();		//再锁银锁				//使用std::lock()				//std::lock(my_mutex1, my_mutex2);    //相当与每个互斥量都调用了lock				//std::lock_guard<mutex>sbguard1(my_mutex1, adopt_lock);				//std::lock_guard<mutex>sbguard2(my_mutex2, adopt_lock);				//std::unique_lock<std::mutex>sbguard1(my_mutex1);				//my_mutex1.lock();                     //in线程后到				//std::unique_lock<std::mutex>sbguard1(my_mutex1,adopt_lock);  //使用了adopt_lock 需要提前lock				//尝试加锁				//std::unique_lock<std::mutex>sbguard1(my_mutex1, std::try_to_lock);         //使用此参数的条件时互斥量没有上锁				//if (sbguard1.owns_lock())              //如果尝试上锁成功				//{   					cout << "inMsgRecvQueue执行,插入一个元素" << i << endl;					//创建没有加锁的my_mutex1					std::unique_lock<std::mutex>sbguard1(my_mutex1, std::defer_lock);					sbguard1.lock();              //不需要手动解锁					msgRecvQueue.push_back(i);     //假设数字i为命令 放入队列				//}				//else								  // 如果上锁失败				//{   				//	cout << "inMsgRecvQueue 执行,但没有上锁。。。。" << endl;				//}									//my_mutex2.unlock();				//顺序无所谓				//my_mutex1.unlock();			}		}	}	bool outMsgLULproc(int &command)	{   		//lock_guard<mutex>sbguard(my_mutex1);       //sbguard是对象名		//my_mutex1.lock();		//my_mutex2.lock();		//std::lock(my_mutex1, my_mutex2);			std::unique_lock<std::mutex>sbguard1(my_mutex1);		std::chrono::milliseconds dura(100);    //等待20s		std::this_thread::sleep_for(dura);		  //休息一定时长  outMsgLULproc先跑起来		if (!msgRecvQueue.empty())		{   		    command = msgRecvQueue.front();      //返回第一个元素但不检查元素是否存在			msgRecvQueue.pop_front();            //移除第一个元素但不返回			//处理数据。。。。。			/*my_mutex1.unlock();			my_mutex2.unlock();*/			return true;		}			else		{   			//my_mutex1.unlock();			//my_mutex2.unlock();			return false; 		}		}	//读取命令的线程	void outMsgRecvQueue()	{   		int command = 0;			for (int i = 0; i < 100000; i++)		{   			bool result = outMsgLULproc(command);			if (result == true)			{   							cout << "outMsgRecvQueue 执行,取出一个元素" << command << endl;				//数据处理			}				}		cout << "end" << endl;		}private:	std::list<int>msgRecvQueue;	mutex my_mutex1;           //创建一个互斥量	mutex my_mutex2;     };int main(){    //   //一 创建线程和等待多个线程	//vector<thread>mythreads;	创建10个线程,线程入口函数统一使用 myprint	1)多线程执行顺序是乱的	2)这种join写法更容易写出稳定程序	3)把thread对象放入到容器里,对管理大量线程有帮助	//for (int i = 0; i < 10; i++)	//{   	//	//创建10个线程,已经开始执行	//	mythreads.push_back(thread(Myprint, i));	//	//}	//for (auto iter = mythreads.begin(); iter != mythreads.end(); ++iter)	//{   	//	iter->join();	//}	//cout << "I LOVE CHINA" << endl;	//二 数据共享	//2.1只读数据	//2.2 有读有写	//最简单的不崩溃处理 读和写不能同时进行	//2.3其他案例	//数据共享:    		//三 共享数据的保护案例代码	//网络游戏服务器,有两个自己创建的线程,一个线程手机玩家命令(数字表示),并把名利数据写入到一个队列中。	//另一个线程从队列中取出玩家发送来的命令,解析,然后执行玩家的动作。	//使用list,频繁的按顺序插入和删除时效率较高	//用成员函数作为线程函数的方法写线程	A myobja;	thread myOutnMsg(&A::outMsgRecvQueue, &myobja);	thread myInMsgObj(&A::inMsgRecvQueue, &myobja);	myOutnMsg.join();	myInMsgObj.join();	//四 互斥量的概念	//步骤:先lock 操作共享数据 然后unlock	//lock和unlock要成对使用。有lock忘记unlock的问题非常难排查	//为了防止忘记unlock(),引入了一个叫std::lock_guard的类模板	//智能指针(unique_ptr<>)	//std::lock_guard类模板 直接取代lock()和unlock(),用了类模板不能再用lock和unlock	//要将保护量放在lock和unlock里	//五 死锁	/*	**死锁问题的前提条件是:有至少两个锁,即至少两个互斥量,金锁(Jinlock),银锁(Yinlock)**	两个线程A,B	线程A执行时,先锁金锁,然后去锁银锁	两个线程出现了上下文切换,线程B执行了,线程B先锁银锁,因为银锁没有被A锁上,所以被B锁上了,然后线程B去锁金锁	此时产生了死锁	线程A锁不了银锁,流程走不下去	线程B锁不了金锁,流程走不下去	死锁产生的关键是两个互斥量的上锁顺序不一致	*/	//5.1死锁演示	//5.2死锁的一般解决方案	//只要保证两个互斥量上锁的顺序一致,就不会造成死锁。	//5.3 std::lock()函数模板	//能力:一次锁住两个或者两个以上的互斥量(至少两个,多了不限,一个不行)	//不存在因为锁头的顺序问题导致出现死锁问题。	//如果互斥量中有一个没锁住,则等待,等待所有互斥量否锁住,才能继续往下走	//特点:要么两个互斥量都锁住,要么两个互斥量都没锁住。如果只锁了一个,另外一个没成功,则立即解锁已经锁住的。	//用来处理多个互斥量的情况	//5.4 std:lock_guard的std:adopt_lock参数	//六 unique_lock取代lock_guard	//unique_lock是个类模板,工作中推荐使用lock_guard	//lock_guard取代了mutex的lock和unlock	//unique_lock比lock_guard灵活,效率略差,内存占用稍多。	//七 unique_lock的第二个参数	// 7.1 adopt_lock	//lock_guard中的adopt_lock起标记作用 表示互斥量已经被lock了,在写这个标记前需要把互斥量lock 否则报错	//adopt的效果是:假设调用方 线程已经拥有了互斥的所有权(已经lock成功了)	//unique_lock也有adopt_lock标记,含义相同。	//灵活性:	//对于同一个锁 如果其中一个线程上了锁,则另一个也需要这个锁的线程就会处于等待状态,知道前一个线程解锁,会浪费很多时间		//7.2 std::try to lock	//尝试用mutex的lock()去锁定lock,但如果没有锁定成功,也会立即返回,并不会阻塞	//用try to lock的前提是不可以手动上锁,否则异常		//7.3 std::defer_lock	//使用defer_lock的前提是 不能自己先lock,否则异常,与try to lock一样,与adopt_lock不同	//defer_lock  初始化一个没有加锁的mutex	//借着defer_lock的话题,介绍一些unique_lock的重要成员函数	//八 unique_lcok的成员函数	// 8.1 lock()}

在这里插入图片描述

3.2 unlock()

解锁:前提是已经加锁

// 并发与多线程2_4.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//#include "pch.h"#include <iostream>#include <vector>#include <thread>#include <list>#include  <mutex>using namespace std;//vector<int>g_v = { 1,2,3 };////void Myprint(int inum)//{   //	cout << "myprint线程开始执行了,线程编号" << inum << endl;//	cout << "myprint线程结束执行了,线程编号" << inum << endl;//	cout << "id 为" << std::this_thread::get_id() << "打印g_v值" << g_v[0] << g_v[1] << g_v[2] << endl;////}class A{   public:	//把玩家命令放入到一个队列的进程	void inMsgRecvQueue()	{   		for (int i = 0; i < 100000; i++)		{   			//my_mutex.lock();						{   				//my_mutex1.lock();		//先锁金锁 实际中两个lock间会执行其他的东西				//my_mutex2.lock();		//再锁银锁				//使用std::lock()				//std::lock(my_mutex1, my_mutex2);    //相当与每个互斥量都调用了lock				//std::lock_guard<mutex>sbguard1(my_mutex1, adopt_lock);				//std::lock_guard<mutex>sbguard2(my_mutex2, adopt_lock);				//std::unique_lock<std::mutex>sbguard1(my_mutex1);				//my_mutex1.lock();                     //in线程后到				//std::unique_lock<std::mutex>sbguard1(my_mutex1,adopt_lock);  //使用了adopt_lock 需要提前lock				//尝试加锁				//std::unique_lock<std::mutex>sbguard1(my_mutex1, std::try_to_lock);         //使用此参数的条件时互斥量没有上锁				//if (sbguard1.owns_lock())              //如果尝试上锁成功				//{   					cout << "inMsgRecvQueue执行,插入一个元素" << i << endl;					//创建没有加锁的my_mutex1					std::unique_lock<std::mutex>sbguard1(my_mutex1, std::defer_lock);					sbguard1.lock();              //不需要手动解锁					//处理共享代码					sbguard1.unlock();              //不需要手动解锁					//处理非共享代码					sbguard1.lock();              //不需要手动解锁					//处理共享代码					msgRecvQueue.push_back(i);     //假设数字i为命令 放入队列				//}				//else								  // 如果上锁失败				//{   				//	cout << "inMsgRecvQueue 执行,但没有上锁。。。。" << endl;				//}									//my_mutex2.unlock();				//顺序无所谓				//my_mutex1.unlock();			}		}	}	bool outMsgLULproc(int &command)	{   		//lock_guard<mutex>sbguard(my_mutex1);       //sbguard是对象名		//my_mutex1.lock();		//my_mutex2.lock();		//std::lock(my_mutex1, my_mutex2);			std::unique_lock<std::mutex>sbguard1(my_mutex1);		std::chrono::milliseconds dura(100);    //等待20s		std::this_thread::sleep_for(dura);		  //休息一定时长  outMsgLULproc先跑起来		if (!msgRecvQueue.empty())		{   		    command = msgRecvQueue.front();      //返回第一个元素但不检查元素是否存在			msgRecvQueue.pop_front();            //移除第一个元素但不返回			//处理数据。。。。。			/*my_mutex1.unlock();			my_mutex2.unlock();*/			return true;		}			else		{   			//my_mutex1.unlock();			//my_mutex2.unlock();			return false; 		}		}	//读取命令的线程	void outMsgRecvQueue()	{   		int command = 0;			for (int i = 0; i < 100000; i++)		{   			bool result = outMsgLULproc(command);			if (result == true)			{   							cout << "outMsgRecvQueue 执行,取出一个元素" << command << endl;				//数据处理			}				}		cout << "end" << endl;		}private:	std::list<int>msgRecvQueue;	mutex my_mutex1;           //创建一个互斥量	mutex my_mutex2;     };int main(){    //   //一 创建线程和等待多个线程	//vector<thread>mythreads;	创建10个线程,线程入口函数统一使用 myprint	1)多线程执行顺序是乱的	2)这种join写法更容易写出稳定程序	3)把thread对象放入到容器里,对管理大量线程有帮助	//for (int i = 0; i < 10; i++)	//{   	//	//创建10个线程,已经开始执行	//	mythreads.push_back(thread(Myprint, i));	//	//}	//for (auto iter = mythreads.begin(); iter != mythreads.end(); ++iter)	//{   	//	iter->join();	//}	//cout << "I LOVE CHINA" << endl;	//二 数据共享	//2.1只读数据	//2.2 有读有写	//最简单的不崩溃处理 读和写不能同时进行	//2.3其他案例	//数据共享:    		//三 共享数据的保护案例代码	//网络游戏服务器,有两个自己创建的线程,一个线程手机玩家命令(数字表示),并把名利数据写入到一个队列中。	//另一个线程从队列中取出玩家发送来的命令,解析,然后执行玩家的动作。	//使用list,频繁的按顺序插入和删除时效率较高	//用成员函数作为线程函数的方法写线程	A myobja;	thread myOutnMsg(&A::outMsgRecvQueue, &myobja);	thread myInMsgObj(&A::inMsgRecvQueue, &myobja);	myOutnMsg.join();	myInMsgObj.join();	//四 互斥量的概念	//步骤:先lock 操作共享数据 然后unlock	//lock和unlock要成对使用。有lock忘记unlock的问题非常难排查	//为了防止忘记unlock(),引入了一个叫std::lock_guard的类模板	//智能指针(unique_ptr<>)	//std::lock_guard类模板 直接取代lock()和unlock(),用了类模板不能再用lock和unlock	//要将保护量放在lock和unlock里	//五 死锁	/*	**死锁问题的前提条件是:有至少两个锁,即至少两个互斥量,金锁(Jinlock),银锁(Yinlock)**	两个线程A,B	线程A执行时,先锁金锁,然后去锁银锁	两个线程出现了上下文切换,线程B执行了,线程B先锁银锁,因为银锁没有被A锁上,所以被B锁上了,然后线程B去锁金锁	此时产生了死锁	线程A锁不了银锁,流程走不下去	线程B锁不了金锁,流程走不下去	死锁产生的关键是两个互斥量的上锁顺序不一致	*/	//5.1死锁演示	//5.2死锁的一般解决方案	//只要保证两个互斥量上锁的顺序一致,就不会造成死锁。	//5.3 std::lock()函数模板	//能力:一次锁住两个或者两个以上的互斥量(至少两个,多了不限,一个不行)	//不存在因为锁头的顺序问题导致出现死锁问题。	//如果互斥量中有一个没锁住,则等待,等待所有互斥量否锁住,才能继续往下走	//特点:要么两个互斥量都锁住,要么两个互斥量都没锁住。如果只锁了一个,另外一个没成功,则立即解锁已经锁住的。	//用来处理多个互斥量的情况	//5.4 std:lock_guard的std:adopt_lock参数	//六 unique_lock取代lock_guard	//unique_lock是个类模板,工作中推荐使用lock_guard	//lock_guard取代了mutex的lock和unlock	//unique_lock比lock_guard灵活,效率略差,内存占用稍多。	//七 unique_lock的第二个参数	// 7.1 adopt_lock	//lock_guard中的adopt_lock起标记作用 表示互斥量已经被lock了,在写这个标记前需要把互斥量lock 否则报错	//adopt的效果是:假设调用方 线程已经拥有了互斥的所有权(已经lock成功了)	//unique_lock也有adopt_lock标记,含义相同。	//灵活性:	//对于同一个锁 如果其中一个线程上了锁,则另一个也需要这个锁的线程就会处于等待状态,知道前一个线程解锁,会浪费很多时间		//7.2 std::try to lock	//尝试用mutex的lock()去锁定lock,但如果没有锁定成功,也会立即返回,并不会阻塞	//用try to lock的前提是不可以手动上锁,否则异常		//7.3 std::defer_lock	//使用defer_lock的前提是 不能自己先lock,否则异常,与try to lock一样,与adopt_lock不同	//defer_lock  初始化一个没有加锁的mutex	//借着defer_lock的话题,介绍一些unique_lock的重要成员函数	//八 unique_lcok的成员函数	// 8.1 lock()	//8.2 unlock()  希望处理些非共享代码,处理非共享代码,然后再lock上	//即unique_lock通过成员函数可以实现手动上锁,自动解锁和手动解锁}

程序稳定运行
在这里插入图片描述

3.3 try_lock

与defer_lock配合使用

// 并发与多线程2_4.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//#include "pch.h"#include <iostream>#include <vector>#include <thread>#include <list>#include  <mutex>using namespace std;//vector<int>g_v = { 1,2,3 };////void Myprint(int inum)//{   //	cout << "myprint线程开始执行了,线程编号" << inum << endl;//	cout << "myprint线程结束执行了,线程编号" << inum << endl;//	cout << "id 为" << std::this_thread::get_id() << "打印g_v值" << g_v[0] << g_v[1] << g_v[2] << endl;////}class A{   public:	//把玩家命令放入到一个队列的进程	void inMsgRecvQueue()	{   		for (int i = 0; i < 100000; i++)		{   			//my_mutex.lock();						{   				//my_mutex1.lock();		//先锁金锁 实际中两个lock间会执行其他的东西				//my_mutex2.lock();		//再锁银锁				//使用std::lock()				//std::lock(my_mutex1, my_mutex2);    //相当与每个互斥量都调用了lock				//std::lock_guard<mutex>sbguard1(my_mutex1, adopt_lock);				//std::lock_guard<mutex>sbguard2(my_mutex2, adopt_lock);				//std::unique_lock<std::mutex>sbguard1(my_mutex1);				//my_mutex1.lock();                     //in线程后到				//std::unique_lock<std::mutex>sbguard1(my_mutex1,adopt_lock);  //使用了adopt_lock 需要提前lock				//尝试加锁				//std::unique_lock<std::mutex>sbguard1(my_mutex1, std::try_to_lock);         //使用此参数的条件时互斥量没有上锁				//if (sbguard1.owns_lock())              //如果尝试上锁成功				//{   										//创建没有加锁的my_mutex1					std::unique_lock<std::mutex>sbguard1(my_mutex1, std::defer_lock);					//sbguard1.lock();              //不需要手动解锁					//处理共享代码					//sbguard1.unlock();              //不需要手动解锁					//处理非共享代码					//sbguard1.lock();              //不需要手动解锁					//处理共享代码					if (sbguard1.try_lock() == true)					{   						cout << "inMsgRecvQueue执行,插入一个元素" << i << endl;						msgRecvQueue.push_back(i);     //假设数字i为命令 放入队列											}					else					{   						cout << "inMsgRecvQueue执行,上锁失败" << endl;											}									//}				//else								  // 如果上锁失败				//{   				//	cout << "inMsgRecvQueue 执行,但没有上锁。。。。" << endl;				//}									//my_mutex2.unlock();				//顺序无所谓				//my_mutex1.unlock();			}		}	}	bool outMsgLULproc(int &command)	{   		//lock_guard<mutex>sbguard(my_mutex1);       //sbguard是对象名		//my_mutex1.lock();		//my_mutex2.lock();		//std::lock(my_mutex1, my_mutex2);			std::unique_lock<std::mutex>sbguard1(my_mutex1);		std::chrono::milliseconds dura(200);    //等待200ms		std::this_thread::sleep_for(dura);		  //休息一定时长  outMsgLULproc先跑起来		if (!msgRecvQueue.empty())		{   		    command = msgRecvQueue.front();      //返回第一个元素但不检查元素是否存在			msgRecvQueue.pop_front();            //移除第一个元素但不返回			//处理数据。。。。。			/*my_mutex1.unlock();			my_mutex2.unlock();*/			return true;		}			else		{   			//my_mutex1.unlock();			//my_mutex2.unlock();			return false; 		}		}	//读取命令的线程	void outMsgRecvQueue()	{   		int command = 0;			for (int i = 0; i < 100000; i++)		{   			bool result = outMsgLULproc(command);			if (result == true)			{   							cout << "outMsgRecvQueue 执行,取出一个元素" << command << endl;				//数据处理			}				}		cout << "end" << endl;		}private:	std::list<int>msgRecvQueue;	mutex my_mutex1;           //创建一个互斥量	mutex my_mutex2;     };int main(){    //   //一 创建线程和等待多个线程	//vector<thread>mythreads;	创建10个线程,线程入口函数统一使用 myprint	1)多线程执行顺序是乱的	2)这种join写法更容易写出稳定程序	3)把thread对象放入到容器里,对管理大量线程有帮助	//for (int i = 0; i < 10; i++)	//{   	//	//创建10个线程,已经开始执行	//	mythreads.push_back(thread(Myprint, i));	//	//}	//for (auto iter = mythreads.begin(); iter != mythreads.end(); ++iter)	//{   	//	iter->join();	//}	//cout << "I LOVE CHINA" << endl;	//二 数据共享	//2.1只读数据	//2.2 有读有写	//最简单的不崩溃处理 读和写不能同时进行	//2.3其他案例	//数据共享:    		//三 共享数据的保护案例代码	//网络游戏服务器,有两个自己创建的线程,一个线程手机玩家命令(数字表示),并把名利数据写入到一个队列中。	//另一个线程从队列中取出玩家发送来的命令,解析,然后执行玩家的动作。	//使用list,频繁的按顺序插入和删除时效率较高	//用成员函数作为线程函数的方法写线程	A myobja;	thread myOutnMsg(&A::outMsgRecvQueue, &myobja);	thread myInMsgObj(&A::inMsgRecvQueue, &myobja);	myOutnMsg.join();	myInMsgObj.join();	//四 互斥量的概念	//步骤:先lock 操作共享数据 然后unlock	//lock和unlock要成对使用。有lock忘记unlock的问题非常难排查	//为了防止忘记unlock(),引入了一个叫std::lock_guard的类模板	//智能指针(unique_ptr<>)	//std::lock_guard类模板 直接取代lock()和unlock(),用了类模板不能再用lock和unlock	//要将保护量放在lock和unlock里	//五 死锁	/*	**死锁问题的前提条件是:有至少两个锁,即至少两个互斥量,金锁(Jinlock),银锁(Yinlock)**	两个线程A,B	线程A执行时,先锁金锁,然后去锁银锁	两个线程出现了上下文切换,线程B执行了,线程B先锁银锁,因为银锁没有被A锁上,所以被B锁上了,然后线程B去锁金锁	此时产生了死锁	线程A锁不了银锁,流程走不下去	线程B锁不了金锁,流程走不下去	死锁产生的关键是两个互斥量的上锁顺序不一致	*/	//5.1死锁演示	//5.2死锁的一般解决方案	//只要保证两个互斥量上锁的顺序一致,就不会造成死锁。	//5.3 std::lock()函数模板	//能力:一次锁住两个或者两个以上的互斥量(至少两个,多了不限,一个不行)	//不存在因为锁头的顺序问题导致出现死锁问题。	//如果互斥量中有一个没锁住,则等待,等待所有互斥量否锁住,才能继续往下走	//特点:要么两个互斥量都锁住,要么两个互斥量都没锁住。如果只锁了一个,另外一个没成功,则立即解锁已经锁住的。	//用来处理多个互斥量的情况	//5.4 std:lock_guard的std:adopt_lock参数	//六 unique_lock取代lock_guard	//unique_lock是个类模板,工作中推荐使用lock_guard	//lock_guard取代了mutex的lock和unlock	//unique_lock比lock_guard灵活,效率略差,内存占用稍多。	//七 unique_lock的第二个参数	// 7.1 adopt_lock	//lock_guard中的adopt_lock起标记作用 表示互斥量已经被lock了,在写这个标记前需要把互斥量lock 否则报错	//adopt的效果是:假设调用方 线程已经拥有了互斥的所有权(已经lock成功了)	//unique_lock也有adopt_lock标记,含义相同。	//灵活性:	//对于同一个锁 如果其中一个线程上了锁,则另一个也需要这个锁的线程就会处于等待状态,知道前一个线程解锁,会浪费很多时间		//7.2 std::try_to_lock	//尝试用mutex的lock()去锁定lock,但如果没有锁定成功,也会立即返回,并不会阻塞	//用try_to_lock的前提是不可以手动上锁,否则异常		//7.3 std::defer_lock	//使用defer_lock的前提是 不能自己先lock,否则异常,与try to lock一样,与adopt_lock不同	//defer_lock  初始化一个没有加锁的mutex	//借着defer_lock的话题,介绍一些unique_lock的重要成员函数	//八 unique_lcok的成员函数	// 8.1 lock()	//8.2 unlock()  希望处理些非共享代码,处理非共享代码,然后再lock上	//即unique_lock通过成员函数可以实现手动上锁,自动解锁和手动解锁	//也可以自己在程序结尾自己家unlock  unique_lock会作出判断	//8.3 try_lock 尝试给互斥量加锁,如果拿不到锁,则返回false,拿到了则返回true,程序不阻塞}

在这里插入图片描述

3.4 release()

// 并发与多线程2_4.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//#include "pch.h"#include <iostream>#include <vector>#include <thread>#include <list>#include  <mutex>using namespace std;//vector<int>g_v = { 1,2,3 };////void Myprint(int inum)//{   //	cout << "myprint线程开始执行了,线程编号" << inum << endl;//	cout << "myprint线程结束执行了,线程编号" << inum << endl;//	cout << "id 为" << std::this_thread::get_id() << "打印g_v值" << g_v[0] << g_v[1] << g_v[2] << endl;////}class A{   public:	//把玩家命令放入到一个队列的进程	void inMsgRecvQueue()	{   		for (int i = 0; i < 100000; i++)		{   			//my_mutex.lock();						{   				//my_mutex1.lock();		//先锁金锁 实际中两个lock间会执行其他的东西				//my_mutex2.lock();		//再锁银锁				//使用std::lock()				//std::lock(my_mutex1, my_mutex2);    //相当与每个互斥量都调用了lock				//std::lock_guard<mutex>sbguard1(my_mutex1, adopt_lock);				//std::lock_guard<mutex>sbguard2(my_mutex2, adopt_lock);				//std::unique_lock<std::mutex>sbguard1(my_mutex1);				//my_mutex1.lock();                     //in线程后到				//std::unique_lock<std::mutex>sbguard1(my_mutex1,adopt_lock);  //使用了adopt_lock 需要提前lock				//尝试加锁				//std::unique_lock<std::mutex>sbguard1(my_mutex1, std::try_to_lock);         //使用此参数的条件时互斥量没有上锁				//if (sbguard1.owns_lock())              //如果尝试上锁成功				//{   										//创建没有加锁的my_mutex1					//std::unique_lock<std::mutex>sbguard1(my_mutex1, std::defer_lock);					//sbguard1.lock();              //不需要手动解锁					//处理共享代码					//sbguard1.unlock();              //不需要手动解锁					//处理非共享代码					//sbguard1.lock();              //不需要手动解锁					//处理共享代码										std::unique_lock<std::mutex>sbguard1(my_mutex1);		// 创建一个加锁的mutex					std::mutex *ptx = sbguard1.release();					//将sbguard1与my_mutex1解绑  手动解锁					//if (sbguard1.try_lock() == true)					//{   						cout << "inMsgRecvQueue执行,插入一个元素" << i << endl;						msgRecvQueue.push_back(i);     //假设数字i为命令 放入队列						ptx->unlock();						//手动解锁									//}					//else					//{   					//	cout << "inMsgRecvQueue执行,上锁失败" << endl;					//						//}									//}				//else								  // 如果上锁失败				//{   				//	cout << "inMsgRecvQueue 执行,但没有上锁。。。。" << endl;				//}									//my_mutex2.unlock();				//顺序无所谓				//my_mutex1.unlock();			}		}	}	bool outMsgLULproc(int &command)	{   		//lock_guard<mutex>sbguard(my_mutex1);       //sbguard是对象名		//my_mutex1.lock();		//my_mutex2.lock();		//std::lock(my_mutex1, my_mutex2);			std::unique_lock<std::mutex>sbguard1(my_mutex1);		std::chrono::milliseconds dura(10);    //等待10ms		std::this_thread::sleep_for(dura);		  //休息一定时长  outMsgLULproc先跑起来		if (!msgRecvQueue.empty())		{   		    command = msgRecvQueue.front();      //返回第一个元素但不检查元素是否存在			msgRecvQueue.pop_front();            //移除第一个元素但不返回			//处理数据。。。。。			/*my_mutex1.unlock();			my_mutex2.unlock();*/			return true;		}			else		{   			//my_mutex1.unlock();			//my_mutex2.unlock();			return false; 		}		}	//读取命令的线程	void outMsgRecvQueue()	{   		int command = 0;			for (int i = 0; i < 100000; i++)		{   			bool result = outMsgLULproc(command);			if (result == true)			{   							cout << "outMsgRecvQueue 执行,取出一个元素" << command << endl;				//数据处理			}				}		cout << "end" << endl;		}private:	std::list<int>msgRecvQueue;	mutex my_mutex1;           //创建一个互斥量	mutex my_mutex2;     };int main(){    //   //一 创建线程和等待多个线程	//vector<thread>mythreads;	创建10个线程,线程入口函数统一使用 myprint	1)多线程执行顺序是乱的	2)这种join写法更容易写出稳定程序	3)把thread对象放入到容器里,对管理大量线程有帮助	//for (int i = 0; i < 10; i++)	//{   	//	//创建10个线程,已经开始执行	//	mythreads.push_back(thread(Myprint, i));	//	//}	//for (auto iter = mythreads.begin(); iter != mythreads.end(); ++iter)	//{   	//	iter->join();	//}	//cout << "I LOVE CHINA" << endl;	//二 数据共享	//2.1只读数据	//2.2 有读有写	//最简单的不崩溃处理 读和写不能同时进行	//2.3其他案例	//数据共享:    		//三 共享数据的保护案例代码	//网络游戏服务器,有两个自己创建的线程,一个线程手机玩家命令(数字表示),并把名利数据写入到一个队列中。	//另一个线程从队列中取出玩家发送来的命令,解析,然后执行玩家的动作。	//使用list,频繁的按顺序插入和删除时效率较高	//用成员函数作为线程函数的方法写线程	A myobja;	thread myOutnMsg(&A::outMsgRecvQueue, &myobja);	thread myInMsgObj(&A::inMsgRecvQueue, &myobja);	myOutnMsg.join();	myInMsgObj.join();	//四 互斥量的概念	//步骤:先lock 操作共享数据 然后unlock	//lock和unlock要成对使用。有lock忘记unlock的问题非常难排查	//为了防止忘记unlock(),引入了一个叫std::lock_guard的类模板	//智能指针(unique_ptr<>)	//std::lock_guard类模板 直接取代lock()和unlock(),用了类模板不能再用lock和unlock	//要将保护量放在lock和unlock里	//五 死锁	/*	**死锁问题的前提条件是:有至少两个锁,即至少两个互斥量,金锁(Jinlock),银锁(Yinlock)**	两个线程A,B	线程A执行时,先锁金锁,然后去锁银锁	两个线程出现了上下文切换,线程B执行了,线程B先锁银锁,因为银锁没有被A锁上,所以被B锁上了,然后线程B去锁金锁	此时产生了死锁	线程A锁不了银锁,流程走不下去	线程B锁不了金锁,流程走不下去	死锁产生的关键是两个互斥量的上锁顺序不一致	*/	//5.1死锁演示	//5.2死锁的一般解决方案	//只要保证两个互斥量上锁的顺序一致,就不会造成死锁。	//5.3 std::lock()函数模板	//能力:一次锁住两个或者两个以上的互斥量(至少两个,多了不限,一个不行)	//不存在因为锁头的顺序问题导致出现死锁问题。	//如果互斥量中有一个没锁住,则等待,等待所有互斥量否锁住,才能继续往下走	//特点:要么两个互斥量都锁住,要么两个互斥量都没锁住。如果只锁了一个,另外一个没成功,则立即解锁已经锁住的。	//用来处理多个互斥量的情况	//5.4 std:lock_guard的std:adopt_lock参数	//六 unique_lock取代lock_guard	//unique_lock是个类模板,工作中推荐使用lock_guard	//lock_guard取代了mutex的lock和unlock	//unique_lock比lock_guard灵活,效率略差,内存占用稍多。	//七 unique_lock的第二个参数	// 7.1 adopt_lock	//lock_guard中的adopt_lock起标记作用 表示互斥量已经被lock了,在写这个标记前需要把互斥量lock 否则报错	//adopt的效果是:假设调用方 线程已经拥有了互斥的所有权(已经lock成功了)	//unique_lock也有adopt_lock标记,含义相同。	//灵活性:	//对于同一个锁 如果其中一个线程上了锁,则另一个也需要这个锁的线程就会处于等待状态,知道前一个线程解锁,会浪费很多时间		//7.2 std::try_to_lock	//尝试用mutex的lock()去锁定lock,但如果没有锁定成功,也会立即返回,并不会阻塞	//用try_to_lock的前提是不可以手动上锁,否则异常		//7.3 std::defer_lock	//使用defer_lock的前提是 不能自己先lock,否则异常,与try to lock一样,与adopt_lock不同	//defer_lock  初始化一个没有加锁的mutex	//借着defer_lock的话题,介绍一些unique_lock的重要成员函数	//八 unique_lcok的成员函数	// 8.1 lock()	//8.2 unlock()  希望处理些非共享代码,处理非共享代码,然后再lock上	//即unique_lock通过成员函数可以实现手动上锁,自动解锁和手动解锁	//也可以自己在程序结尾自己家unlock  unique_lock会作出判断	//8.3 try_lock 尝试给互斥量加锁,如果拿不到锁,则返回false,拿到了则返回true,程序不阻塞	//8.4 release(),返回它管理的mutex对象指针,并释放所有权,也就是说,这个unique_lock和mutex不再有关系	//严格区分unlock()和release()的区别,不要混淆	//如果原来mutex对象处于加锁状态,如果release了,则需要手动解锁	//release返回原始的mutex指针	//为什么有时候需要unlock():因为lock锁住的代码段越少,执行越快,整个程序运行效率越高	//乘互斥量锁住的代码多少,称为粒度 ,粒度一般用粗细描述	//要选择合适粒度的代码来保护共享数据,粒度太细影响效率,粒度太粗影响效率	}

在这里插入图片描述

4.unique_lock所有权的传递

一个mutex只和一个mutex绑定在一起
所有权概念: sbguard1拥有my_mutex1的所有权,sbguard1可以把对my_mutex1的所有权转一个其他unique_lock对象,
所以,unique_lock的所有权,可以转移,不能复制。
std::unique_lockstd::mutexsbguard1(my_mutex1);
std::unique_lockstd::mutexsbguard2(sbguard1); 这样是非法的
std::unique_lockstd::mutexsbguard2(std::move(sbguard1)); //将sbguard1的所有权转移给sbguard2

4.1 调用std::move转移所有权

// 并发与多线程2_4.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。#include "pch.h"#include <iostream>#include <vector>#include <thread>#include <list>#include  <mutex>using namespace std;//vector<int>g_v = { 1,2,3 };////void Myprint(int inum)//{   //	cout << "myprint线程开始执行了,线程编号" << inum << endl;//	cout << "myprint线程结束执行了,线程编号" << inum << endl;//	cout << "id 为" << std::this_thread::get_id() << "打印g_v值" << g_v[0] << g_v[1] << g_v[2] << endl;////}class A{   public:	//把玩家命令放入到一个队列的进程	void inMsgRecvQueue()	{   		for (int i = 0; i < 100000; i++)		{   			//my_mutex.lock();						{   				//my_mutex1.lock();		//先锁金锁 实际中两个lock间会执行其他的东西				//my_mutex2.lock();		//再锁银锁				//使用std::lock()				//std::lock(my_mutex1, my_mutex2);    //相当与每个互斥量都调用了lock				//std::lock_guard<mutex>sbguard1(my_mutex1, adopt_lock);				//std::lock_guard<mutex>sbguard2(my_mutex2, adopt_lock);				//std::unique_lock<std::mutex>sbguard1(my_mutex1);				//my_mutex1.lock();                     //in线程后到				//std::unique_lock<std::mutex>sbguard1(my_mutex1,adopt_lock);  //使用了adopt_lock 需要提前lock				//尝试加锁				//std::unique_lock<std::mutex>sbguard1(my_mutex1, std::try_to_lock);         //使用此参数的条件时互斥量没有上锁				//if (sbguard1.owns_lock())              //如果尝试上锁成功				//{   										//创建没有加锁的my_mutex1					//std::unique_lock<std::mutex>sbguard1(my_mutex1, std::defer_lock);					//sbguard1.lock();              //不需要手动解锁					//处理共享代码					//sbguard1.unlock();              //不需要手动解锁					//处理非共享代码					//sbguard1.lock();              //不需要手动解锁					//处理共享代码										std::unique_lock<std::mutex>sbguard1(my_mutex1);		// 创建一个加锁的mutex					std::unique_lock<std::mutex>sbguard2(std::move(sbguard1)); //将sbguard1的所有权转移给sbguard2					//现在sbguard1指向空 sbguard2指向了my_mutex1					/*std::mutex *ptx = sbguard1.release();	*/				//将sbguard1与my_mutex1解绑  手动解锁					//if (sbguard1.try_lock() == true)					//{   						cout << "inMsgRecvQueue执行,插入一个元素" << i << endl;						msgRecvQueue.push_back(i);     //假设数字i为命令 放入队列						sbguard2.unlock();						//手动解锁									//}					//else					//{   					//	cout << "inMsgRecvQueue执行,上锁失败" << endl;					//						//}									//}				//else								  // 如果上锁失败				//{   				//	cout << "inMsgRecvQueue 执行,但没有上锁。。。。" << endl;				//}									//my_mutex2.unlock();				//顺序无所谓				//my_mutex1.unlock();			}		}	}	bool outMsgLULproc(int &command)	{   		//lock_guard<mutex>sbguard(my_mutex1);       //sbguard是对象名		//my_mutex1.lock();		//my_mutex2.lock();		//std::lock(my_mutex1, my_mutex2);			std::unique_lock<std::mutex>sbguard1(my_mutex1);		std::chrono::milliseconds dura(10);    //等待10ms		std::this_thread::sleep_for(dura);		  //休息一定时长  outMsgLULproc先跑起来		if (!msgRecvQueue.empty())		{   		    command = msgRecvQueue.front();      //返回第一个元素但不检查元素是否存在			msgRecvQueue.pop_front();            //移除第一个元素但不返回			//处理数据。。。。。			/*my_mutex1.unlock();			my_mutex2.unlock();*/			return true;		}			else		{   			//my_mutex1.unlock();			//my_mutex2.unlock();			return false; 		}		}	//读取命令的线程	void outMsgRecvQueue()	{   		int command = 0;			for (int i = 0; i < 100000; i++)		{   			bool result = outMsgLULproc(command);			if (result == true)			{   							cout << "outMsgRecvQueue 执行,取出一个元素" << command << endl;				//数据处理			}				}		cout << "end" << endl;		}private:	std::list<int>msgRecvQueue;	mutex my_mutex1;           //创建一个互斥量	mutex my_mutex2;     };int main(){    //   //一 创建线程和等待多个线程	//vector<thread>mythreads;	创建10个线程,线程入口函数统一使用 myprint	1)多线程执行顺序是乱的	2)这种join写法更容易写出稳定程序	3)把thread对象放入到容器里,对管理大量线程有帮助	//for (int i = 0; i < 10; i++)	//{   	//	//创建10个线程,已经开始执行	//	mythreads.push_back(thread(Myprint, i));	//	//}	//for (auto iter = mythreads.begin(); iter != mythreads.end(); ++iter)	//{   	//	iter->join();	//}	//cout << "I LOVE CHINA" << endl;	//二 数据共享	//2.1只读数据	//2.2 有读有写	//最简单的不崩溃处理 读和写不能同时进行	//2.3其他案例	//数据共享:    		//三 共享数据的保护案例代码	//网络游戏服务器,有两个自己创建的线程,一个线程手机玩家命令(数字表示),并把名利数据写入到一个队列中。	//另一个线程从队列中取出玩家发送来的命令,解析,然后执行玩家的动作。	//使用list,频繁的按顺序插入和删除时效率较高	//用成员函数作为线程函数的方法写线程	A myobja;	thread myOutnMsg(&A::outMsgRecvQueue, &myobja);	thread myInMsgObj(&A::inMsgRecvQueue, &myobja);	myOutnMsg.join();	myInMsgObj.join();	//四 互斥量的概念	//步骤:先lock 操作共享数据 然后unlock	//lock和unlock要成对使用。有lock忘记unlock的问题非常难排查	//为了防止忘记unlock(),引入了一个叫std::lock_guard的类模板	//智能指针(unique_ptr<>)	//std::lock_guard类模板 直接取代lock()和unlock(),用了类模板不能再用lock和unlock	//要将保护量放在lock和unlock里	//五 死锁	/*	**死锁问题的前提条件是:有至少两个锁,即至少两个互斥量,金锁(Jinlock),银锁(Yinlock)**	两个线程A,B	线程A执行时,先锁金锁,然后去锁银锁	两个线程出现了上下文切换,线程B执行了,线程B先锁银锁,因为银锁没有被A锁上,所以被B锁上了,然后线程B去锁金锁	此时产生了死锁	线程A锁不了银锁,流程走不下去	线程B锁不了金锁,流程走不下去	死锁产生的关键是两个互斥量的上锁顺序不一致	*/	//5.1死锁演示	//5.2死锁的一般解决方案	//只要保证两个互斥量上锁的顺序一致,就不会造成死锁。	//5.3 std::lock()函数模板	//能力:一次锁住两个或者两个以上的互斥量(至少两个,多了不限,一个不行)	//不存在因为锁头的顺序问题导致出现死锁问题。	//如果互斥量中有一个没锁住,则等待,等待所有互斥量否锁住,才能继续往下走	//特点:要么两个互斥量都锁住,要么两个互斥量都没锁住。如果只锁了一个,另外一个没成功,则立即解锁已经锁住的。	//用来处理多个互斥量的情况	//5.4 std:lock_guard的std:adopt_lock参数	//六 unique_lock取代lock_guard	//unique_lock是个类模板,工作中推荐使用lock_guard	//lock_guard取代了mutex的lock和unlock	//unique_lock比lock_guard灵活,效率略差,内存占用稍多。	//七 unique_lock的第二个参数	// 7.1 adopt_lock	//lock_guard中的adopt_lock起标记作用 表示互斥量已经被lock了,在写这个标记前需要把互斥量lock 否则报错	//adopt的效果是:假设调用方 线程已经拥有了互斥的所有权(已经lock成功了)	//unique_lock也有adopt_lock标记,含义相同。	//灵活性:	//对于同一个锁 如果其中一个线程上了锁,则另一个也需要这个锁的线程就会处于等待状态,知道前一个线程解锁,会浪费很多时间		//7.2 std::try_to_lock	//尝试用mutex的lock()去锁定lock,但如果没有锁定成功,也会立即返回,并不会阻塞	//用try_to_lock的前提是不可以手动上锁,否则异常		//7.3 std::defer_lock	//使用defer_lock的前提是 不能自己先lock,否则异常,与try to lock一样,与adopt_lock不同	//defer_lock  初始化一个没有加锁的mutex	//借着defer_lock的话题,介绍一些unique_lock的重要成员函数	//八 unique_lcok的成员函数	// 8.1 lock()	//8.2 unlock()  希望处理些非共享代码,处理非共享代码,然后再lock上	//即unique_lock通过成员函数可以实现手动上锁,自动解锁和手动解锁	//也可以自己在程序结尾自己家unlock  unique_lock会作出判断	//8.3 try_lock 尝试给互斥量加锁,如果拿不到锁,则返回false,拿到了则返回true,程序不阻塞	//8.4 release(),返回它管理的mutex对象指针,并释放所有权,也就是说,这个unique_lock和mutex不再有关系	//严格区分unlock()和release()的区别,不要混淆	//如果原来mutex对象处于加锁状态,如果release了,则需要手动解锁	//release返回原始的mutex指针	//为什么有时候需要unlock():因为lock锁住的代码段越少,执行越快,整个程序运行效率越高	//乘互斥量锁住的代码多少,称为粒度 ,粒度一般用粗细描述	//要选择合适粒度的代码来保护共享数据,粒度太细影响效率,粒度太粗影响效率		// 九 unique_lock的所有权传递	// 一个mutex只和一个mutex绑定在一起  	//所有权概念: sbguard1拥有my_mutex1的所有权,sbguard1可以把对my_mutex1的所有权转一个其他unique_lock对象,	//所以,unique_lock的所有权,可以转移,不能复制。	//std::unique_lock<std::mutex>sbguard1(my_mutex1);	//std::unique_lock<std::mutex>sbguard2(sbguard1);  这样是非法的	//std::unique_lock<std::mutex>sbguard2(std::move(sbguard1)); //将sbguard1的所有权转移给sbguard2}

在这里插入图片描述
在这里插入图片描述

4.2 使用A的类成员函数返回unique_lock对象

// 并发与多线程2_4.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//#include "pch.h"#include <iostream>#include <vector>#include <thread>#include <list>#include  <mutex>using namespace std;//vector<int>g_v = { 1,2,3 };////void Myprint(int inum)//{   //	cout << "myprint线程开始执行了,线程编号" << inum << endl;//	cout << "myprint线程结束执行了,线程编号" << inum << endl;//	cout << "id 为" << std::this_thread::get_id() << "打印g_v值" << g_v[0] << g_v[1] << g_v[2] << endl;////}class A{   public:	//把玩家命令放入到一个队列的进程	std::unique_lock<std::mutex>rtn_unique_lock()	{   		std::unique_lock<std::mutex>temguard(my_mutex1);		return temguard;		//从函数返回一个局部的unique_lock对象是可以的,移动构造函数		//返回这种局部对象temguard会导致系统生成临时unique_lock对象,并调用unique_lock的移动构造函数		}	void inMsgRecvQueue()	{   		for (int i = 0; i < 100000; i++)		{   			//my_mutex.lock();						{   				//my_mutex1.lock();		//先锁金锁 实际中两个lock间会执行其他的东西				//my_mutex2.lock();		//再锁银锁				//使用std::lock()				//std::lock(my_mutex1, my_mutex2);    //相当与每个互斥量都调用了lock				//std::lock_guard<mutex>sbguard1(my_mutex1, adopt_lock);				//std::lock_guard<mutex>sbguard2(my_mutex2, adopt_lock);				//std::unique_lock<std::mutex>sbguard1(my_mutex1);				//my_mutex1.lock();                     //in线程后到				//std::unique_lock<std::mutex>sbguard1(my_mutex1,adopt_lock);  //使用了adopt_lock 需要提前lock				//尝试加锁				//std::unique_lock<std::mutex>sbguard1(my_mutex1, std::try_to_lock);         //使用此参数的条件时互斥量没有上锁				//if (sbguard1.owns_lock())              //如果尝试上锁成功				//{   										//创建没有加锁的my_mutex1					//std::unique_lock<std::mutex>sbguard1(my_mutex1, std::defer_lock);					//sbguard1.lock();              //不需要手动解锁					//处理共享代码					//sbguard1.unlock();              //不需要手动解锁					//处理非共享代码					//sbguard1.lock();              //不需要手动解锁					//处理共享代码										//std::unique_lock<std::mutex>sbguard1(my_mutex1);		// 创建一个加锁的mutex					//std::unique_lock<std::mutex>sbguard2(std::move(sbguard1)); //将sbguard1的所有权转移给sbguard2					//现在sbguard1指向空 sbguard2指向了my_mutex1					/*std::mutex *ptx = sbguard1.release();	*/				//将sbguard1与my_mutex1解绑  手动解锁					//if (sbguard1.try_lock() == true)					//{   					std::unique_lock<std::mutex>sbguard1 = rtn_unique_lock();						cout << "inMsgRecvQueue执行,插入一个元素" << i << endl;						msgRecvQueue.push_back(i);     //假设数字i为命令 放入队列						sbguard1.unlock();						//手动解锁									//}					//else					//{   					//	cout << "inMsgRecvQueue执行,上锁失败" << endl;					//						//}									//}				//else								  // 如果上锁失败				//{   				//	cout << "inMsgRecvQueue 执行,但没有上锁。。。。" << endl;				//}									//my_mutex2.unlock();				//顺序无所谓				//my_mutex1.unlock();			}		}	}	bool outMsgLULproc(int &command)	{   		//lock_guard<mutex>sbguard(my_mutex1);       //sbguard是对象名		//my_mutex1.lock();		//my_mutex2.lock();		//std::lock(my_mutex1, my_mutex2);			std::unique_lock<std::mutex>sbguard1(my_mutex1);		std::chrono::milliseconds dura(10);    //等待10ms		std::this_thread::sleep_for(dura);		  //休息一定时长  outMsgLULproc先跑起来		if (!msgRecvQueue.empty())		{   		    command = msgRecvQueue.front();      //返回第一个元素但不检查元素是否存在			msgRecvQueue.pop_front();            //移除第一个元素但不返回			//处理数据。。。。。			/*my_mutex1.unlock();			my_mutex2.unlock();*/			return true;		}			else		{   			//my_mutex1.unlock();			//my_mutex2.unlock();			return false; 		}		}	//读取命令的线程	void outMsgRecvQueue()	{   		int command = 0;			for (int i = 0; i < 100000; i++)		{   			bool result = outMsgLULproc(command);			if (result == true)			{   							cout << "outMsgRecvQueue 执行,取出一个元素" << command << endl;				//数据处理			}				}		cout << "end" << endl;		}private:	std::list<int>msgRecvQueue;	mutex my_mutex1;           //创建一个互斥量	mutex my_mutex2;     };int main(){    //   //一 创建线程和等待多个线程	//vector<thread>mythreads;	创建10个线程,线程入口函数统一使用 myprint	1)多线程执行顺序是乱的	2)这种join写法更容易写出稳定程序	3)把thread对象放入到容器里,对管理大量线程有帮助	//for (int i = 0; i < 10; i++)	//{   	//	//创建10个线程,已经开始执行	//	mythreads.push_back(thread(Myprint, i));	//	//}	//for (auto iter = mythreads.begin(); iter != mythreads.end(); ++iter)	//{   	//	iter->join();	//}	//cout << "I LOVE CHINA" << endl;	//二 数据共享	//2.1只读数据	//2.2 有读有写	//最简单的不崩溃处理 读和写不能同时进行	//2.3其他案例	//数据共享:    		//三 共享数据的保护案例代码	//网络游戏服务器,有两个自己创建的线程,一个线程手机玩家命令(数字表示),并把名利数据写入到一个队列中。	//另一个线程从队列中取出玩家发送来的命令,解析,然后执行玩家的动作。	//使用list,频繁的按顺序插入和删除时效率较高	//用成员函数作为线程函数的方法写线程	A myobja;	thread myOutnMsg(&A::outMsgRecvQueue, &myobja);	thread myInMsgObj(&A::inMsgRecvQueue, &myobja);	myOutnMsg.join();	myInMsgObj.join();	//四 互斥量的概念	//步骤:先lock 操作共享数据 然后unlock	//lock和unlock要成对使用。有lock忘记unlock的问题非常难排查	//为了防止忘记unlock(),引入了一个叫std::lock_guard的类模板	//智能指针(unique_ptr<>)	//std::lock_guard类模板 直接取代lock()和unlock(),用了类模板不能再用lock和unlock	//要将保护量放在lock和unlock里	//五 死锁	/*	**死锁问题的前提条件是:有至少两个锁,即至少两个互斥量,金锁(Jinlock),银锁(Yinlock)**	两个线程A,B	线程A执行时,先锁金锁,然后去锁银锁	两个线程出现了上下文切换,线程B执行了,线程B先锁银锁,因为银锁没有被A锁上,所以被B锁上了,然后线程B去锁金锁	此时产生了死锁	线程A锁不了银锁,流程走不下去	线程B锁不了金锁,流程走不下去	死锁产生的关键是两个互斥量的上锁顺序不一致	*/	//5.1死锁演示	//5.2死锁的一般解决方案	//只要保证两个互斥量上锁的顺序一致,就不会造成死锁。	//5.3 std::lock()函数模板	//能力:一次锁住两个或者两个以上的互斥量(至少两个,多了不限,一个不行)	//不存在因为锁头的顺序问题导致出现死锁问题。	//如果互斥量中有一个没锁住,则等待,等待所有互斥量否锁住,才能继续往下走	//特点:要么两个互斥量都锁住,要么两个互斥量都没锁住。如果只锁了一个,另外一个没成功,则立即解锁已经锁住的。	//用来处理多个互斥量的情况	//5.4 std:lock_guard的std:adopt_lock参数	//六 unique_lock取代lock_guard	//unique_lock是个类模板,工作中推荐使用lock_guard	//lock_guard取代了mutex的lock和unlock	//unique_lock比lock_guard灵活,效率略差,内存占用稍多。	//七 unique_lock的第二个参数	// 7.1 adopt_lock	//lock_guard中的adopt_lock起标记作用 表示互斥量已经被lock了,在写这个标记前需要把互斥量lock 否则报错	//adopt的效果是:假设调用方 线程已经拥有了互斥的所有权(已经lock成功了)	//unique_lock也有adopt_lock标记,含义相同。	//灵活性:	//对于同一个锁 如果其中一个线程上了锁,则另一个也需要这个锁的线程就会处于等待状态,知道前一个线程解锁,会浪费很多时间		//7.2 std::try_to_lock	//尝试用mutex的lock()去锁定lock,但如果没有锁定成功,也会立即返回,并不会阻塞	//用try_to_lock的前提是不可以手动上锁,否则异常		//7.3 std::defer_lock	//使用defer_lock的前提是 不能自己先lock,否则异常,与try to lock一样,与adopt_lock不同	//defer_lock  初始化一个没有加锁的mutex	//借着defer_lock的话题,介绍一些unique_lock的重要成员函数	//八 unique_lcok的成员函数	// 8.1 lock()	//8.2 unlock()  希望处理些非共享代码,处理非共享代码,然后再lock上	//即unique_lock通过成员函数可以实现手动上锁,自动解锁和手动解锁	//也可以自己在程序结尾自己家unlock  unique_lock会作出判断	//8.3 try_lock 尝试给互斥量加锁,如果拿不到锁,则返回false,拿到了则返回true,程序不阻塞	//8.4 release(),返回它管理的mutex对象指针,并释放所有权,也就是说,这个unique_lock和mutex不再有关系	//严格区分unlock()和release()的区别,不要混淆	//如果原来mutex对象处于加锁状态,如果release了,则需要手动解锁	//release返回原始的mutex指针	//为什么有时候需要unlock():因为lock锁住的代码段越少,执行越快,整个程序运行效率越高	//乘互斥量锁住的代码多少,称为粒度 ,粒度一般用粗细描述	//要选择合适粒度的代码来保护共享数据,粒度太细影响效率,粒度太粗影响效率		// 九 unique_lock的所有权传递	// 一个mutex只和一个mutex绑定在一起  	//所有权概念: sbguard1拥有my_mutex1的所有权,sbguard1可以把对my_mutex1的所有权转一个其他unique_lock对象,	//所以,unique_lock的所有权,可以转移,不能复制。	//std::unique_lock<std::mutex>sbguard1(my_mutex1);	//std::unique_lock<std::mutex>sbguard2(sbguard1);  这样是非法的	//std::unique_lock<std::mutex>sbguard2(std::move(sbguard1)); //将sbguard1的所有权转移给sbguard2}

在这里插入图片描述
在这里插入图片描述
可以看到my_mutex1的地址被绑定到了sbguard1上了

转载地址:http://nwfr.baihongyu.com/

你可能感兴趣的文章
常用的IDC函数
查看>>
BUUCTF 新年快乐 内涵的软件 Java逆向解密 刮开有奖
查看>>
虎符杯——虚拟机逆向
查看>>
angr学习笔记(7)(malloc地址单元符号化)
查看>>
angr学习笔记(9)(添加约束)
查看>>
angr学习笔记(13)(static_binary)
查看>>
windows环境利用start命令实现微信多开
查看>>
「CF149D」括号涂色 区间DP好题
查看>>
树状数组 模板总结
查看>>
「NOI2015」程序自动分析 并查集题解
查看>>
[JSOI2008]Blue Mary的战役地图 Hash题解
查看>>
Ubuntu修改终端上显示的用户名和主机名(详细步骤)
查看>>
教你写一手漂亮的伪代码(详细规则&简单实例)
查看>>
MySQL的基本体系和架构介绍
查看>>
MySQL数据备份实践和整理
查看>>
结构型设计在工作中的一些经验总结
查看>>
如何提升员工体验 助力企业业务增长?这个棘手的问题终于被解决了!
查看>>
腾讯物联网操作系统正式开源,最小体积仅1.8 KB
查看>>
不懂数据库的码农不是好程序员!
查看>>
全球首个!阿里云开源批流一体机器学习平台Alink……
查看>>