一: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:帶超時功能的遞歸獨佔互斥量(允許同一個線程多次獲取這個互斥量)