6-12 windows臨界區、其他各種mutex互斥量

一:windows臨界區

二:多次進入臨界區試驗

在“同一個線程”(不同線程就會卡住等待)中,windows中的"相同臨界區變量“代表的臨界區的進入(EnterCriticalSection)可以被調用多次
但是你調用了幾次EnterCriticalSection,你就得調用幾次LeaveCriticalSection(&my_winsec);

class A
{
public:
	//把收到的消息(玩家命令)入到一個隊列的線程
	void inMsgRecvQueue()
	{
		for(int i = 0;i<100000;++i)
		{
			cout<<"inMsgRecvQueue()執行,插入一個元素"<<i<<endl;
#ifdef_WINDOWSJQ_
	EnterCriticalSection(&my_winsec);	//進入臨界區(加鎖)
	EnterCrticalSection(&my_winsec);
	msgRecvQueue.push_back(i);
	LeaveCriticalSection(&my_winsec);	//離開臨界區(解鎖)
	LeaveCriticalSection(&my_winsec);
#endif
			//my_mutex2.lock();		//死鎖,這邊先2後1,下邊先1後2
			//my_mutex1.lock();	//實際工程中這兩個鎖頭不一定挨着,們需要保護不同的數據共享塊;
			std::lock(my_mutex1,my_mutex2);	//相當於每個互斥量都調用了.lock();
			std::lock_guard<std::mutex> sbguard(my_mutex1,std::adopt_lock);	//這樣能省略自己unlock的步驟
			std::lock_guard<std::mutex> sbguard(my_mutex2,std::adopt_lock);
			std::lock_guard<std::resursive_mutex> sbguard(my_mutex);
			std::chrono::milliseconds timeout(100);	//100毫秒
			//if(my_mutex.try_lock_for(timeout))	//等待100毫秒來嘗試獲取鎖
			if(my_mutex.try_lock_unitl(chrono::steady_clock::now()+timeout))
			{
				//在這100毫秒之內拿到了鎖
			}
			else
			{
				//這次沒拿到鎖頭
				std::chrono::microseconds sleeptime(100);
				std::this_thread::sleep_for(sleeptime);
			}
			msgRecvQueue.push_back(i);//假設這個數字i就是我收到的命令,我直接弄到消息隊列裏邊來;
			//my_mutex.unlock();
		}
		return;
	}
	bool out MsgLULProc(int &command)
	{
		std::lock_guard<std::mutex> sbguard(my_mutex);//sbguard是隨便起的對象名
		//lock_guard構造函數裏執行了mutex::lock(),析構函數裏執行了mutex::unlock();
		//my_mutex1.lock();		//死鎖
		//my_mutex2.lock();
		//std::lock(my_mutex1,my_mutex2);	//相當於每個互斥量都調用了.lock();
		if(!msgRecvQueue.empty())
		{
			//消息不爲空
			int command = msgRecvQueue.front();	//返回第一個元素,但不檢查元素是否存在
			msgRecvQueue.pop_front();	//移除第一個元素
			//my_mutex.unlock();	//一定不能忘記return前的解鎖
			return true;
		}
		//my_mutex.unlock();
		return false;
	}
	//把數據從消息隊列中取出的線程
	void outMsgRecvQueue()
	{
		int command = 0;
		for(int i = 0;i<10000;i++)
		{
			bool result = outMsgLULProc(command);
			if(result == true)
			{
				cout<<"out執行了,取出一個元素"<<command<<endl;
			}
			else
			{
				cout<<"消息隊列爲空"<<i<<endl;
			}
			/*if(!msgRecvQueue.empty())
			{
				//消息不爲空
				int command = msgRecvQueue.front();//返回第一個元素,但不檢查元素是否存在;
				msgRecvQueue.pop_front();	//移除第一個元素,但不返回;
				//這裏就考慮處理數據....
				//....
			}
			else
			{
				//消息隊列爲空
				cout<<"消息隊列爲空"<<i<<endl;
			}*/
		}
		cout<<"end"<<endl;
	}
private:
std::list<int> msgRecvQueue;//容器,專門用於代表玩家給咱們發送過來的命令。
std::mutex my_mutex;	//創建了一個互斥量
std::recursive_mutex my_mutex;	//遞歸式獨佔互斥量
std::timed_mutex my_mutex;	//帶超時功能的獨佔互斥量;
};

int main()
{
	A myobja;
	std::thread myOutnMsgObj(&A::outMsgRecvQueue, &myobja);//第二個參數是引用才能保證用的是同一個對象
	std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);//
	myOutnMsgObj.join();
	myInMsgObj.join();
}

三:自動釋鎖技術

//本類用於自動釋放windows下的臨界區,防止忘記LeaveCriticalSection導致死鎖情況的發生,類似於C++11中的lock_guard
classCWinLock{		//叫RAII類(Resource Acquisition is initialization)中文”資源獲取即初始化“;
public:
	CWinLock(CRITICAL_SECTION *pCritmp)	//構造函數
	{
		m_pCritical = pCritmp;
		EnterCriticalSection(&m_pCritical);
	}
	~CWinLock()	//析構函數
	{
		LeaveCriticalSection(m_pCritical);
	}

}

四:recursive_mutex遞歸的獨佔互斥量

std::mutex:獨佔互斥量,自己lock時別人lock不了;
recursive_mutex:遞歸的獨佔互斥量:允許同一個線程,同一個互斥量多次被.lock()
recursive_mutex也有lock(),也有unlock();
考慮代碼是否有優化空間。
遞歸次數據說有限制,遞歸太多次可能報異常。

五:帶超時的互斥量std::timed_mutex和std::recursive_timed_mutex

std::timed_mutex:是帶超時功能的獨佔互斥量;
try_lock_for(): 參數是一段時間,是等待一段時間。如果我拿到了鎖,或者或者等待超過時間沒拿到鎖,就走下來;
try_lock_unit():參數是一個未來的時間點,在這個未來的時間沒到的時間內
如果時間到了沒拿到鎖,程序流程也走下來;

std::recursive_timed_mutex:帶超時功能的遞歸獨佔互斥量(允許同一個線程多次獲取這個互斥量)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章