17.12 windows临界区、其他各种mutex互斥量

初始代码如下

class MA
{
public:
	//把收到的消息(玩家命令)放入到一个队列的线程
	void inMsgRecvQueue()
	{
		for (int i = 0; i < 100000; ++i)
		{
			cout << "inMsgRecvQueue()执行,插入一个元素: " << i << endl;
			my_mutex.lock();
			msgRecvQueue.push_back(i);  //假设这个数字i就是我收到的命令,直接弄到消息队列中
			my_mutex.unlock();
		}
	}

	bool outMsgLUProc(int& command)
	{
		my_mutex.lock();
		if (!msgRecvQueue.empty())
		{
			//消息不为空
			command = msgRecvQueue.front();  //返回第一个元素,但不检查元素是否存在;
			msgRecvQueue.pop_front();  //移除第一个元素,但不返回
			my_mutex.unlock();
			return true;
	}
		my_mutex.unlock();
		return false;
}

	//把数据从消息队列中取出的线程
	void outMsgRecvQueue()
	{
		int command = 0;
		for (int i = 0; i < 100000; ++i)
		{
			bool result = outMsgLUProc(command);
			if (result == true)
			{
				cout << "outMsgRecvQueue()执行,取出一个元素" << endl;
				//这里就考虑处理数据...
				//...
			}
			else
			{
				cout << "outMsgRecvQueue()执行,但目前消息队列中为空 " << i << endl;
			}
		}
		cout << "end" << endl;
	}

private:
	list<int> msgRecvQueue;  //容器(消息队列),专门用于代表玩家发送的命令
	std::mutex my_mutex;  //创建了一个互斥量
};

int main()
{
	MA myobj;
	std::thread myOutMsgObj(&MA::outMsgRecvQueue, &myobj);  //第二个参数是引用,才能保证线程里用的是同一个对象
	std::thread myInMsgObj(&MA::inMsgRecvQueue, &myobj);
	myOutMsgObj.join();
	myInMsgObj.join();
	cout << "main主函数执行结束" << endl;  //最后执行这句,整个进程退出
	return 0;
}

一:windows临界区

#include <list>
#include <future>
#include <iostream>
#include <windows.h>

using namespace std;

#define __WINDOWSJQ_  //定义一个开关,WINDOWS开关

class MA
{
public:
	//把收到的消息(玩家命令)放入到一个队列的线程
	void inMsgRecvQueue()
	{
		for (int i = 0; i < 100000; ++i)
		{
			cout << "inMsgRecvQueue()执行,插入一个元素: " << i << endl;

#ifdef __WINDOWSJQ_ 
			EnterCriticalSection(&my_winsec);  //进入临界区(加锁)
			msgRecvQueue.push_back(i);  //假设这个数字i就是我收到的命令,直接弄到消息队列中
			LeaveCriticalSection(&my_winsec);  //离开临界区(解锁)
#else
			my_mutex.lock();
			msgRecvQueue.push_back(i);  //假设这个数字i就是我收到的命令,直接弄到消息队列中
			my_mutex.unlock();
#endif
		}
	}

	bool outMsgLUProc(int& command)
	{
#ifdef __WINDOWSJQ_ 
		EnterCriticalSection(&my_winsec);  //进入临界区(加锁)
		if (!msgRecvQueue.empty())
		{
			//消息不为空
			command = msgRecvQueue.front();  //返回第一个元素,但不检查元素是否存在;
			msgRecvQueue.pop_front();  //移除第一个元素,但不返回
			LeaveCriticalSection(&my_winsec);  //离开临界区(解锁)
			return true;
		}
		LeaveCriticalSection(&my_winsec);  //离开临界区(解锁)
#else
		my_mutex.lock();
		if (!msgRecvQueue.empty())
		{
			//消息不为空
			command = msgRecvQueue.front();  //返回第一个元素,但不检查元素是否存在;
			msgRecvQueue.pop_front();  //移除第一个元素,但不返回
			my_mutex.unlock();
			return true;
		}
		my_mutex.unlock();
#endif
		return false;
	}

	//把数据从消息队列中取出的线程
	void outMsgRecvQueue()
	{
		int command = 0;
		for (int i = 0; i < 100000; ++i)
		{
			bool result = outMsgLUProc(command);
			if (result == true)
			{
				cout << "outMsgRecvQueue()执行,取出一个元素" << endl;
				//这里就考虑处理数据...
				//...
			}
			else
			{
				cout << "outMsgRecvQueue()执行,但目前消息队列中为空 " << i << endl;
			}
		}
		cout << "end" << endl;
	}

	MA()
	{
#ifdef __WINDOWSJQ_ 
		InitializeCriticalSection(&my_winsec);  //用临界区之前要先初始化
#endif
	}

private:
	list<int> msgRecvQueue;  //容器(消息队列),专门用于代表玩家发送的命令
	std::mutex my_mutex;  //创建了一个互斥量
#ifdef __WINDOWSJQ_  //解开开关
	CRITICAL_SECTION my_winsec;  //windwos中的临界区,非常类似于c++11中的mutex
#endif
};

int main()
{
	MA myobj;
	std::thread myOutMsgObj(&MA::outMsgRecvQueue, &myobj);  //第二个参数是引用,才能保证线程里用的是同一个对象
	std::thread myInMsgObj(&MA::inMsgRecvQueue, &myobj);
	myOutMsgObj.join();
	myInMsgObj.join();
	cout << "main主函数执行结束" << endl;  //最后执行这句,整个进程退出
	return 0;
}

二:多次进入临界区试验

在同一线程中(不同线程就会卡住等待)中,windows中的“相同临界区变量”代表的临界区的进入EnterCriticalSection()可以被多次调用。但是调用几次EnterCriticalSection(),就得调用几次LeaveCriticalSection()。

#define __WINDOWSJQ_  //定义一个开关,WINDOWS开关

class MA
{
public:
	//把收到的消息(玩家命令)放入到一个队列的线程
	void inMsgRecvQueue()
	{
		for (int i = 0; i < 100000; ++i)
		{
			cout << "inMsgRecvQueue()执行,插入一个元素: " << i << endl;

#ifdef __WINDOWSJQ_ 
			EnterCriticalSection(&my_winsec);  //进入临界区(加锁)
			EnterCriticalSection(&my_winsec);  //两次进入临界区(加锁)
			msgRecvQueue.push_back(i);  //假设这个数字i就是我收到的命令,直接弄到消息队列中
			LeaveCriticalSection(&my_winsec);  //离开临界区(解锁)
			LeaveCriticalSection(&my_winsec);  //两次进入必须两次离开
#else
			my_mutex.lock();
			msgRecvQueue.push_back(i);  //假设这个数字i就是我收到的命令,直接弄到消息队列中
			my_mutex.unlock();
#endif
		}
	}

	bool outMsgLUProc(int& command)
	{
#ifdef __WINDOWSJQ_ 
		EnterCriticalSection(&my_winsec);  //进入临界区(加锁)
		if (!msgRecvQueue.empty())
		{
			//消息不为空
			command = msgRecvQueue.front();  //返回第一个元素,但不检查元素是否存在;
			msgRecvQueue.pop_front();  //移除第一个元素,但不返回
			LeaveCriticalSection(&my_winsec);  //离开临界区(解锁)
			return true;
		}
		LeaveCriticalSection(&my_winsec);  //离开临界区(解锁)
#else
		my_mutex.lock();
		if (!msgRecvQueue.empty())
		{
			//消息不为空
			command = msgRecvQueue.front();  //返回第一个元素,但不检查元素是否存在;
			msgRecvQueue.pop_front();  //移除第一个元素,但不返回
			my_mutex.unlock();
			return true;
		}
		my_mutex.unlock();
#endif
		return false;
	}

	//把数据从消息队列中取出的线程
	void outMsgRecvQueue()
	{
		int command = 0;
		for (int i = 0; i < 100000; ++i)
		{
			bool result = outMsgLUProc(command);
			if (result == true)
			{
				cout << "outMsgRecvQueue()执行,取出一个元素" << endl;
				//这里就考虑处理数据...
				//...
			}
			else
			{
				cout << "outMsgRecvQueue()执行,但目前消息队列中为空 " << i << endl;
			}
		}
		cout << "end" << endl;
	}

	MA()
	{
#ifdef __WINDOWSJQ_ 
		InitializeCriticalSection(&my_winsec);  //用临界区之前要先初始化
#endif
	}

private:
	list<int> msgRecvQueue;  //容器(消息队列),专门用于代表玩家发送的命令
	std::mutex my_mutex;  //创建了一个互斥量
#ifdef __WINDOWSJQ_  //解开开关
	CRITICAL_SECTION my_winsec;  //windwos中的临界区,非常类似于c++11中的mutex
#endif
};

int main()
{
	MA myobj;
	std::thread myOutMsgObj(&MA::outMsgRecvQueue, &myobj);  //第二个参数是引用,才能保证线程里用的是同一个对象
	std::thread myInMsgObj(&MA::inMsgRecvQueue, &myobj);
	myOutMsgObj.join();
	myInMsgObj.join();
	cout << "main主函数执行结束" << endl;  //最后执行这句,整个进程退出
	return 0;
}

在c++11中加两次锁就会报错,不允许同一个线程中lock同一个互斥量多次,否则报异常。

my_mutex.lock();
my_mutex.lock();  //报异常,和windows有区别
msgRecvQueue.push_back(i);     
my_mutex.unlock();
my_mutex.unlock();

三:自动析构技术

std::lock_guardstd::mutex
std::lock_guardstd::mutex sbguard(my_mutex);
std::lock_guardstd::mutex sbguard1(my_mutex);
lock_guard也不能调用两次

using namespace std;

//#define __WINDOWSJQ_  //定义一个开关,WINDOWS开关

class MA
{
public:
	//把收到的消息(玩家命令)放入到一个队列的线程
	void inMsgRecvQueue()
	{
		for (int i = 0; i < 100000; ++i)
		{
			cout << "inMsgRecvQueue()执行,插入一个元素: " << i << endl;

#ifdef __WINDOWSJQ_ 
			EnterCriticalSection(&my_winsec);  //进入临界区(加锁)
			EnterCriticalSection(&my_winsec);  //两次进入临界区(加锁)
			msgRecvQueue.push_back(i);  //假设这个数字i就是我收到的命令,直接弄到消息队列中
			LeaveCriticalSection(&my_winsec);  //离开临界区(解锁)
			LeaveCriticalSection(&my_winsec);  //两次进入必须两次离开
#else
			std::lock_guard<std::mutex> sbguard(my_mutex);
			std::lock_guard<std::mutex> sbguard1(my_mutex);
			msgRecvQueue.push_back(i);  //假设这个数字i就是我收到的命令,直接弄到消息队列中
#endif
		}
	}

	bool outMsgLUProc(int& command)
	{
#ifdef __WINDOWSJQ_ 
		EnterCriticalSection(&my_winsec);  //进入临界区(加锁)
		if (!msgRecvQueue.empty())
		{
			//消息不为空
			command = msgRecvQueue.front();  //返回第一个元素,但不检查元素是否存在;
			msgRecvQueue.pop_front();  //移除第一个元素,但不返回
			LeaveCriticalSection(&my_winsec);  //离开临界区(解锁)
			return true;
		}
		LeaveCriticalSection(&my_winsec);  //离开临界区(解锁)
#else
		my_mutex.lock();
		if (!msgRecvQueue.empty())
		{
			//消息不为空
			command = msgRecvQueue.front();  //返回第一个元素,但不检查元素是否存在;
			msgRecvQueue.pop_front();  //移除第一个元素,但不返回
			my_mutex.unlock();
			return true;
		}
		my_mutex.unlock();
#endif
		return false;
	}

	//把数据从消息队列中取出的线程
	void outMsgRecvQueue()
	{
		int command = 0;
		for (int i = 0; i < 100000; ++i)
		{
			bool result = outMsgLUProc(command);
			if (result == true)
			{
				cout << "outMsgRecvQueue()执行,取出一个元素" << endl;
				//这里就考虑处理数据...
				//...
			}
			else
			{
				cout << "outMsgRecvQueue()执行,但目前消息队列中为空 " << i << endl;
			}
		}
		cout << "end" << endl;
	}

	MA()
	{
#ifdef __WINDOWSJQ_ 
		InitializeCriticalSection(&my_winsec);  //用临界区之前要先初始化
#endif
	}

private:
	list<int> msgRecvQueue;  //容器(消息队列),专门用于代表玩家发送的命令
	std::mutex my_mutex;  //创建了一个互斥量
#ifdef __WINDOWSJQ_  //解开开关
	CRITICAL_SECTION my_winsec;  //windwos中的临界区,非常类似于c++11中的mutex
#endif
};

int main()
{
	MA myobj;
	std::thread myOutMsgObj(&MA::outMsgRecvQueue, &myobj);  //第二个参数是引用,才能保证线程里用的是同一个对象
	std::thread myInMsgObj(&MA::inMsgRecvQueue, &myobj);
	myOutMsgObj.join();
	myInMsgObj.join();
	cout << "main主函数执行结束" << endl;  //最后执行这句,整个进程退出
	return 0;
}

自动释放windows下的临界区,防止忘记LeaveCriticalSection()导致死锁情况的发生,类似于c++11中的std::lock_guardstd::mutex功能。

#define __WINDOWSJQ_  //定义一个开关,WINDOWS开关

//本类用于自动释放windows下的临界区,防止忘记LeaveCriticalSection()导致死锁情况的发生,类似于c++11中的std::lock_guard<std::mutex>功能
class CWinLock  //叫RAII类(Resourse Acquisition is initialization)中文“资源获取及初始化”。容器、智能指针这种类,都属于RAII类
{     
public:
	CWinLock(CRITICAL_SECTION* pCripem)  //构造函数
	{   
		m_pCritical = pCripem;
		EnterCriticalSection(m_pCritical);
	}
	~CWinLock()  //析构函数
	{   
		LeaveCriticalSection(m_pCritical);
	}
private:
	CRITICAL_SECTION* m_pCritical;
};

class MA
{
public:
	//把收到的消息(玩家命令)放入到一个队列的线程
	void inMsgRecvQueue()
	{
		for (int i = 0; i < 100000; ++i)
		{
			cout << "inMsgRecvQueue()执行,插入一个元素: " << i << endl;

#ifdef __WINDOWSJQ_ 
			CWinLock wlock(&my_winsec);  //wlock,wlock2都属于RAII类
			CWinLock wlock2(&my_winsec);  //wlock,wlock2都属于RAII类
			msgRecvQueue.push_back(i);  //假设这个数字i就是我收到的命令,直接弄到消息队列中
#else
			std::lock_guard<std::mutex> sbguard(my_mutex);
			msgRecvQueue.push_back(i);  //假设这个数字i就是我收到的命令,直接弄到消息队列中
#endif
		}
	}

	bool outMsgLUProc(int& command)
	{
#ifdef __WINDOWSJQ_ 
		EnterCriticalSection(&my_winsec);  //进入临界区(加锁)
		if (!msgRecvQueue.empty())
		{
			//消息不为空
			command = msgRecvQueue.front();  //返回第一个元素,但不检查元素是否存在;
			msgRecvQueue.pop_front();  //移除第一个元素,但不返回
			LeaveCriticalSection(&my_winsec);  //离开临界区(解锁)
			return true;
		}
		LeaveCriticalSection(&my_winsec);  //离开临界区(解锁)
#else
		my_mutex.lock();
		if (!msgRecvQueue.empty())
		{
			//消息不为空
			command = msgRecvQueue.front();  //返回第一个元素,但不检查元素是否存在;
			msgRecvQueue.pop_front();  //移除第一个元素,但不返回
			my_mutex.unlock();
			return true;
		}
		my_mutex.unlock();
#endif
		return false;
	}

	//把数据从消息队列中取出的线程
	void outMsgRecvQueue()
	{
		int command = 0;
		for (int i = 0; i < 100000; ++i)
		{
			bool result = outMsgLUProc(command);
			if (result == true)
			{
				cout << "outMsgRecvQueue()执行,取出一个元素" << endl;
				//这里就考虑处理数据...
				//...
			}
			else
			{
				cout << "outMsgRecvQueue()执行,但目前消息队列中为空 " << i << endl;
			}
		}
		cout << "end" << endl;
	}

	MA()
	{
#ifdef __WINDOWSJQ_ 
		InitializeCriticalSection(&my_winsec);  //用临界区之前要先初始化
#endif
	}

private:
	list<int> msgRecvQueue;  //容器(消息队列),专门用于代表玩家发送的命令
	std::mutex my_mutex;  //创建了一个互斥量
#ifdef __WINDOWSJQ_  //解开开关
	CRITICAL_SECTION my_winsec;  //windwos中的临界区,非常类似于c++11中的mutex
#endif
};

int main()
{
	MA myobj;
	std::thread myOutMsgObj(&MA::outMsgRecvQueue, &myobj);  //第二个参数是引用,才能保证线程里用的是同一个对象
	std::thread myInMsgObj(&MA::inMsgRecvQueue, &myobj);
	myOutMsgObj.join();
	myInMsgObj.join();
	cout << "main主函数执行结束" << endl;  //最后执行这句,整个进程退出
	return 0;
}

四:recursive_mutex递归的独占互斥量

std::mutex:独占互斥量,自己lock时,别人就lock不了。
recursive_mutex:递归的独占互斥量。允许同一个线程,同一个互斥量多次被lock()。效率上比mutex要差一些。

std::lock_guardstd::recursive_mutex sbguard(my_mutex);
testfun1();

如果出现recursive_mutex,就要考虑代码的效率是不是有问题,最好能不使用。递归次数有限制,递归太多可能报异常。

//#define __WINDOWSJQ_  //定义一个开关,WINDOWS开关

//本类用于自动释放windows下的临界区,防止忘记LeaveCriticalSection()导致死锁情况的发生,类似于c++11中的std::lock_guard<std::mutex>功能
class CWinLock  //叫RAII类(Resourse Acquisition is initialization)中文“资源获取及初始化”。容器、智能指针这种类,都属于RAII类
{
public:
	CWinLock(CRITICAL_SECTION* pCripem)  //构造函数
	{
		m_pCritical = pCripem;
		EnterCriticalSection(m_pCritical);
	}
	~CWinLock()  //析构函数
	{
		LeaveCriticalSection(m_pCritical);
	}
private:
	CRITICAL_SECTION* m_pCritical;
};

class MA
{
public:
	//把收到的消息(玩家命令)放入到一个队列的线程
	void inMsgRecvQueue()
	{
		for (int i = 0; i < 100000; ++i)
		{
			cout << "inMsgRecvQueue()执行,插入一个元素: " << i << endl;

#ifdef __WINDOWSJQ_ 
			CWinLock wlock(&my_winsec);  //wlock,wlock2都属于RAII类
			CWinLock wlock2(&my_winsec);  //wlock,wlock2都属于RAII类
			msgRecvQueue.push_back(i);  //假设这个数字i就是我收到的命令,直接弄到消息队列中
#else
			std::lock_guard<std::recursive_mutex> sbguard(my_mutex);
			testfun1();  //加了三次锁,报异常(只要lock超过1次就报异常)
			msgRecvQueue.push_back(i);  //假设这个数字i就是我收到的命令,直接弄到消息队列中
#endif
		}
	}

	bool outMsgLUProc(int& command)
	{
#ifdef __WINDOWSJQ_ 
		EnterCriticalSection(&my_winsec);  //进入临界区(加锁)
		if (!msgRecvQueue.empty())
		{
			//消息不为空
			command = msgRecvQueue.front();  //返回第一个元素,但不检查元素是否存在;
			msgRecvQueue.pop_front();  //移除第一个元素,但不返回
			LeaveCriticalSection(&my_winsec);  //离开临界区(解锁)
			return true;
		}
		LeaveCriticalSection(&my_winsec);  //离开临界区(解锁)
#else
		my_mutex.lock();
		if (!msgRecvQueue.empty())
		{
			//消息不为空
			command = msgRecvQueue.front();  //返回第一个元素,但不检查元素是否存在;
			msgRecvQueue.pop_front();  //移除第一个元素,但不返回
			my_mutex.unlock();
			return true;
		}
		my_mutex.unlock();
#endif
		return false;
	}

	//把数据从消息队列中取出的线程
	void outMsgRecvQueue()
	{
		int command = 0;
		for (int i = 0; i < 100000; ++i)
		{
			bool result = outMsgLUProc(command);
			if (result == true)
			{
				cout << "outMsgRecvQueue()执行,取出一个元素" << endl;
				//这里就考虑处理数据...
				//...
			}
			else
			{
				cout << "outMsgRecvQueue()执行,但目前消息队列中为空 " << i << endl;
			}
		}
		cout << "end" << endl;
	}

	MA()
	{
#ifdef __WINDOWSJQ_ 
		InitializeCriticalSection(&my_winsec);  //用临界区之前要先初始化
#endif
	}

	void testfun1()
	{
		std::lock_guard<std::recursive_mutex> sbguard(my_mutex);
		//干一些事情
		testfun2();  //奔溃
	}
	void testfun2()
	{
		std::lock_guard<std::recursive_mutex> sbguard(my_mutex);
		//干另一些事情
	}

private:
	list<int> msgRecvQueue;  //容器(消息队列),专门用于代表玩家发送的命令
	//std::mutex my_mutex;  //创建了一个互斥量
	std::recursive_mutex my_mutex;  //递归式的独占互斥量
#ifdef __WINDOWSJQ_  //解开开关
	CRITICAL_SECTION my_winsec;  //windwos中的临界区,非常类似于c++11中的mutex
#endif
};

int main()
{
	MA myobj;
	std::thread myOutMsgObj(&MA::outMsgRecvQueue, &myobj);  //第二个参数是引用,才能保证线程里用的是同一个对象
	std::thread myInMsgObj(&MA::inMsgRecvQueue, &myobj);
	myOutMsgObj.join();
	myInMsgObj.join();
	cout << "main主函数执行结束" << endl;  //最后执行这句,整个进程退出
	return 0;
}

五:带超时的互斥量std::time_mutex和std::recursive_timed_mutex

<1>std::timed_mutex :带超时功能的独占互斥量

try_lock_for():参数是等待一段时间。如果我拿到了锁,或者等待超过时间没拿到锁头,就走下来;

//#define __WINDOWSJQ_  //定义一个开关,WINDOWS开关

//本类用于自动释放windows下的临界区,防止忘记LeaveCriticalSection()导致死锁情况的发生,类似于c++11中的std::lock_guard<std::mutex>功能
class CWinLock  //叫RAII类(Resourse Acquisition is initialization)中文“资源获取及初始化”。容器、智能指针这种类,都属于RAII类
{
public:
	CWinLock(CRITICAL_SECTION* pCripem)  //构造函数
	{
		m_pCritical = pCripem;
		EnterCriticalSection(m_pCritical);
	}
	~CWinLock()  //析构函数
	{
		LeaveCriticalSection(m_pCritical);
	}
private:
	CRITICAL_SECTION* m_pCritical;
};

class MA
{
public:
	//把收到的消息(玩家命令)放入到一个队列的线程
	void inMsgRecvQueue()
	{
		for (int i = 0; i < 100000; ++i)
		{
			cout << "inMsgRecvQueue()执行,插入一个元素: " << i << endl;

#ifdef __WINDOWSJQ_ 
			CWinLock wlock(&my_winsec);  //wlock,wlock2都属于RAII类
			CWinLock wlock2(&my_winsec);  //wlock,wlock2都属于RAII类
			msgRecvQueue.push_back(i);  //假设这个数字i就是我收到的命令,直接弄到消息队列中
#else
			std::chrono::milliseconds timeout(100);  //100毫秒
			if (my_mutex.try_lock_for(timeout))  //等待一百毫秒尝试获取锁头 
			{
				//在这100毫秒之内拿到了锁
				msgRecvQueue.push_back(i);
				my_mutex.unlock();  //用完了要解锁;
			}
			else
			{
				//这次没拿到锁头
				std::chrono::milliseconds sleeptime(100);
				std::this_thread::sleep_for(sleeptime);
			}
			msgRecvQueue.push_back(i);  //假设这个数字i就是我收到的命令,直接弄到消息队列中
#endif
		}
	}

	bool outMsgLUProc(int& command)
	{
#ifdef __WINDOWSJQ_ 
		EnterCriticalSection(&my_winsec);  //进入临界区(加锁)
		if (!msgRecvQueue.empty())
		{
			//消息不为空
			command = msgRecvQueue.front();  //返回第一个元素,但不检查元素是否存在;
			msgRecvQueue.pop_front();  //移除第一个元素,但不返回
			LeaveCriticalSection(&my_winsec);  //离开临界区(解锁)
			return true;
		}
		LeaveCriticalSection(&my_winsec);  //离开临界区(解锁)
#else
		my_mutex.lock();
		std::chrono::milliseconds sleeptime(1000000);
		std::this_thread::sleep_for(sleeptime);
		if (!msgRecvQueue.empty())
		{
			//消息不为空
			command = msgRecvQueue.front();  //返回第一个元素,但不检查元素是否存在;
			msgRecvQueue.pop_front();  //移除第一个元素,但不返回
			my_mutex.unlock();
			return true;
		}
		my_mutex.unlock();
#endif
		return false;
	}

	//把数据从消息队列中取出的线程
	void outMsgRecvQueue()
	{
		int command = 0;
		for (int i = 0; i < 100000; ++i)
		{
			bool result = outMsgLUProc(command);
			if (result == true)
			{
				cout << "outMsgRecvQueue()执行,取出一个元素" << endl;
				//这里就考虑处理数据...
				//...
			}
			else
			{
				cout << "outMsgRecvQueue()执行,但目前消息队列中为空 " << i << endl;
			}
		}
		cout << "end" << endl;
	}

	MA()
	{
#ifdef __WINDOWSJQ_ 
		InitializeCriticalSection(&my_winsec);  //用临界区之前要先初始化
#endif
}

private:
	list<int> msgRecvQueue;  //容器(消息队列),专门用于代表玩家发送的命令
	//std::mutex my_mutex;  //创建了一个互斥量
	std::timed_mutex my_mutex;  //带超时功能的独占互斥量
#ifdef __WINDOWSJQ_  //解开开关
	CRITICAL_SECTION my_winsec;  //windwos中的临界区,非常类似于c++11中的mutex
#endif
};

int main()
{
	MA myobj;
	std::thread myOutMsgObj(&MA::outMsgRecvQueue, &myobj);  //第二个参数是引用,才能保证线程里用的是同一个对象
	std::thread myInMsgObj(&MA::inMsgRecvQueue, &myobj);
	myOutMsgObj.join();
	myInMsgObj.join();
	cout << "main主函数执行结束" << endl;  //最后执行这句,整个进程退出
	return 0;
}

try_lock_until():参数是一个未来的时间点,在这个未来时间没到的时间段内。如果拿到了锁,那么就走下来;如果时间到了,没拿到锁,程序流程也走下来。

	void inMsgRecvQueue()
	{
		for (int i = 0; i < 100000; ++i)
		{
			cout << "inMsgRecvQueue()执行,插入一个元素: " << i << endl;

#ifdef __WINDOWSJQ_ 
			CWinLock wlock(&my_winsec);  //wlock,wlock2都属于RAII类
			CWinLock wlock2(&my_winsec);  //wlock,wlock2都属于RAII类
			msgRecvQueue.push_back(i);  //假设这个数字i就是我收到的命令,直接弄到消息队列中
#else
			std::chrono::milliseconds timeout(100);  //100毫秒
			if (my_mutex.try_lock_until(chrono::steady_clock::now() + timeout))
			{
				//在这100毫秒之内拿到了锁
				msgRecvQueue.push_back(i);
				my_mutex.unlock();  //用完了要解锁;
			}
			else
			{
				//这次没拿到锁头
				std::chrono::milliseconds sleeptime(100);
				std::this_thread::sleep_for(sleeptime);
			}
			msgRecvQueue.push_back(i);  //假设这个数字i就是我收到的命令,直接弄到消息队列中
#endif
		}
	}

<2>std::recursive_timed_mutex:带超时功能的递归独占互斥量(允许同一个线程多次获取这个互斥量)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值