window临界区以及其他各种mutex互斥量

#include "pch.h"
#include <iostream>
#include <thread>
#include <vector>
#include <list>
#include <mutex>
#include <windows.h>
using namespace std;

//开关
//# define __WINDOWSJQ_

//本类用于自动释放windows下的临界区,防止忘记LeaveCriticalSection导致死锁情况的发生,类似于C++11中的lock_guard
class CWinlock   //叫RAII类(Resource Asquisition is initialization ),该类生成的对象叫RAII对象  //资源获取即初始化
{
public:
	CWinlock(CRITICAL_SECTION *pCritmp)  //构造函数进入临界区
	{
		m_pCritical = pCritmp;
		EnterCriticalSection(m_pCritical);

	}
	~CWinlock()   //析构函数离开临界区
	{
		LeaveCriticalSection(m_pCritical);
	}
private:
	CRITICAL_SECTION * m_pCritical;
};

//具备mutex的类
class A_Mutex {
public:
	A_Mutex()   //在构造函数将临界区初始化
	{
#ifdef __WINDOWSJQ_
		InitializeCriticalSection(&my_winsec);  //用临界区之前要先初始化
#endif // __WINDOWSJQ_

	}
	void inMsgRecvQueue()  //把收到的消息(玩家命令)到一个队列的线程。100000次便于观察
	{
		for (int i = 0; i < 100000; i++)
		{
			cout << "inMsgRecvQueue()执行,插入一个元素" << i << endl;

#ifdef __WINDOWSJQ_
			
			//EnterCriticalSection(&my_winsec);    //进入临界区(加锁)
			//EnterCriticalSection(&my_winsec);    //同一线程中可以多次进入临界区
			CWinlock wlock(&my_winsec);    //自动离开临界区
			CWinlock wlock2(&my_winsec);    //也可以多次进入
			msgRecvQueue.push_back(i);
			//LeaveCriticalSection(&my_winsec);    //离开临界区(解锁)
			//LeaveCriticalSection(&my_winsec);    //进入几次就需要离开几次

#else
				//...处理代码
			   	//my_mutex.lock();
				//my_mutex.lock();          //同一线程不可以对同一个互斥量lock两次,除非是recursive的互斥量
				//msgRecvQueue.push_back(i); //假设这个数字i就是我收到的命令,直接送到消息队列里去
				//my_mutex.unlock();
				//my_mutex.unlock();

			    //带超时功能的独占互斥量
			chrono::milliseconds timeout(100); //100毫秒
			//if (my_mutex.try_lock_for(timeout))  //try_lock_for,在这100毫秒内拿到了锁
		  if (my_mutex.try_lock_until(chrono::steady_clock::now()+timeout))  //try_lock_until,在未来的时间点到来前拿到了锁(这里设置的是当前时间后的100毫秒)
			{
				
				msgRecvQueue.push_back(i);
				my_mutex.unlock(); //用完后解锁
			}
			else
			{
				//暂未拿到锁
				chrono::milliseconds sleeptime(100); //100毫秒
				this_thread::sleep_for(sleeptime);
			}

#endif // __WINDOWSJQ_

			//....处理其他代码

		}
		return;
	}

	bool outMsgLULProc(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;
		}
		//注意这里也有一个unlock(另外一个出口也需要unlock)
		my_mutex.unlock();
#endif
		return false;

	}
	void outMsgRecvQueue()//把数据从消息队列中取出的线程
	{
		int command = 0;
		for (int i = 0; i < 100000; i++)
		{
			if (outMsgLULProc(command) == true)
			{
				cout << "outMsgRecvQueue()执行" << i << endl;
				//可以对command进行数据处理
			}
			else
			{
				//消息队列为空
				cout << "outMsgRecvQueue()执行,但目前消息队列为空" << i << endl;
			}
		}
		cout << "end" << endl;
		return;
	}
private:
	list <int> msgRecvQueue; //容器(消息队列),专门用于代表玩家发送过来的命令
	//mutex my_mutex; //创建了一个独占互斥量(一个锁)
	//recursive_mutex my_mutex;    //创建了一个递归的独占互斥量
	timed_mutex my_mutex;    //带超时功能的独占互斥量
#ifdef __WINDOWSJQ_
	CRITICAL_SECTION my_winsec;   //windows中的临界区,类似于C++11的mutex 
#endif // __WINDOWSJQ_

};


int main()
{
	//一:windows临界区


	//二:多次进入临界区试验
	//在同一线程中(不同的线程中则需等待),windows中的“相同临界区变量”代表的临界区的进入可以被多次调用。N次调用就需要N次释放。
	//而C++中,同一线程不可以对同一个互斥量lock两次


	//三:自动析构技术


	//四:recursive_mutex 递归的独占互斥量
	//允许同一线程,对同一互斥量多次lock,效率上比mutex低,消耗更大
	//尽量优化代码,减少上锁次数


	//五:带超时的互斥量timed_mutex和recursive_timed_mutex
	//timed_mutex:带超时功能的独占互斥量。
			//try_lock_for():等待一段时间。如果拿到了锁或者等待超过时间(未拿到锁),流程走下来
			//try_lock_until():等待直至一个未来的时间点。如果提前拿到了锁或者直至未来的时间还未拿到锁,流程走下来
	//recursive_timed_mutex:带超时功能的递归独占互斥量



	A_Mutex myobja;
	thread myOutnMsgObj(&A_Mutex::outMsgRecvQueue,&myobja);  //第二参数是引用(就无需拷贝),才能保证线程里用的是同一对象
	thread myInMsgobj(&A_Mutex::inMsgRecvQueue, &myobja);
	myOutnMsgObj.join();
	myInMsgobj.join();
	cout << "主线程执行完毕" << endl; //执行完这句,主线程退出


	


	return 0;

}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值