秒殺多線程-關(guān)鍵段CS
CRITICAL_SECTION
函數(shù)功能:初始化
函數(shù)原型:
函數(shù)說(shuō)明:定義關(guān)鍵段變量后必須先初始化。
函數(shù)功能:銷毀
函數(shù)原型:
函數(shù)說(shuō)明:用完之后記得銷毀。
函數(shù)功能:進(jìn)入關(guān)鍵區(qū)域
函數(shù)原型:
函數(shù)說(shuō)明:系統(tǒng)保證各線程互斥的進(jìn)入關(guān)鍵區(qū)域。
函數(shù)功能:離開關(guān)關(guān)鍵區(qū)域
函數(shù)原型:
使用實(shí)例
然后在經(jīng)典多線程問(wèn)題中設(shè)置兩個(gè)關(guān)鍵區(qū)域。一個(gè)是主線程在遞增子線程序號(hào)時(shí),另一個(gè)是各子線程互斥的訪問(wèn)輸出全局資源時(shí)。詳見(jiàn)代碼:

可以看出來(lái),各子線程已經(jīng)可以互斥的訪問(wèn)與輸出全局資源了,但主線程與子線程之間的同步還是有點(diǎn)問(wèn)題。
分別在兩個(gè)地方打斷點(diǎn)調(diào)試:

正常來(lái)說(shuō),兩個(gè)斷點(diǎn)應(yīng)該是依次輪流執(zhí)行,但實(shí)際會(huì)多次執(zhí)行EnterCriticalSection(&g_csParent);
分析問(wèn)題
先找到關(guān)鍵段CRITICAL_SECTION
的定義吧,它在minwinbase.h中被定義成RTL_CRITICAL_SECTION
。而RTL_CRITICAL_SECTION
在winnt.h中聲明,它其實(shí)是個(gè)結(jié)構(gòu)體:
參數(shù)說(shuō)明:PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
調(diào)試用的。
LONG LockCount;
初始化為-1,-n表示有n個(gè)線程在等待。
LONG RecursionCount;
表示該關(guān)鍵段的擁有線程對(duì)此資源獲得關(guān)鍵段次數(shù),初為0,每進(jìn)入一次關(guān)鍵區(qū)域加一。
HANDLE OwningThread;
即擁有該關(guān)鍵段的線程句柄
HANDLE LockSemaphore;
實(shí)際上是一個(gè)自復(fù)位事件。
ULONG_PTR SpinCount;
旋轉(zhuǎn)鎖的設(shè)置,單CPU下忽略
由這個(gè)結(jié)構(gòu)可以知道關(guān)鍵段會(huì)記錄擁有該關(guān)鍵段的線程句柄即關(guān)鍵段是有“線程所有權(quán)”概念的。事實(shí)上它會(huì)用第四個(gè)參數(shù)OwningThread
來(lái)記錄獲準(zhǔn)進(jìn)入關(guān)鍵區(qū)域的線程句柄,如果這個(gè)線程再次進(jìn)入,EnterCriticalSection()
會(huì)更新第三個(gè)參數(shù)RecursionCount
以記錄該線程進(jìn)入的次數(shù)并立即返回讓該線程進(jìn)入。其它線程調(diào)用EnterCriticalSection()
則會(huì)被切換到等待狀態(tài),一旦擁有線程所有權(quán)的線程調(diào)用LeaveCriticalSection()
使其進(jìn)入的次數(shù)為0時(shí),系統(tǒng)會(huì)自動(dòng)更新關(guān)鍵段并將等待中的線程換回可調(diào)度狀態(tài)。
因此可以將關(guān)鍵段比作旅館的房卡,調(diào)用EnterCriticalSection()
即申請(qǐng)房卡,得到房卡后自己當(dāng)然是可以多次進(jìn)出房間的,在你調(diào)用LeaveCriticalSection()
交出房卡之前,別人自然是無(wú)法進(jìn)入該房間。
回到這個(gè)經(jīng)典線程同步問(wèn)題上,主線程正是由于擁有“線程所有權(quán)”即房卡,所以它可以重復(fù)進(jìn)入關(guān)鍵代碼區(qū)域從而導(dǎo)致子線程在接收參數(shù)之前主線程就已經(jīng)修改了這個(gè)參數(shù)。所以關(guān)鍵段可以用于線程間的互斥,但不可以用于同步。
另外,由于將線程切換到等待狀態(tài)的開銷較大,因此為了提高關(guān)鍵段的性能,Microsoft將旋轉(zhuǎn)鎖合并到關(guān)鍵段中,這樣EnterCriticalSection()
會(huì)先用一個(gè)旋轉(zhuǎn)鎖不斷循環(huán),嘗試一段時(shí)間才會(huì)將線程切換到等待狀態(tài)。
配合了旋轉(zhuǎn)鎖的關(guān)鍵段初始化函數(shù)
函數(shù)功能:初始化關(guān)鍵段并設(shè)置旋轉(zhuǎn)次數(shù)函數(shù)原型:
函數(shù)說(shuō)明:旋轉(zhuǎn)次數(shù)一般設(shè)置為4000。
函數(shù)功能:修改關(guān)鍵段的旋轉(zhuǎn)次數(shù)
函數(shù)原型:
《Windows核心編程》第五版的第八章推薦在使用關(guān)鍵段的時(shí)候同時(shí)使用旋轉(zhuǎn)鎖,這樣有助于提高性能。值得注意的是如果主機(jī)只有一個(gè)處理器,那么設(shè)置旋轉(zhuǎn)鎖是無(wú)效的。無(wú)法進(jìn)入關(guān)鍵區(qū)域的線程總會(huì)被系統(tǒng)將其切換到等待狀態(tài)。
總結(jié)關(guān)鍵段CS
1.關(guān)鍵段共初始化、銷毀、進(jìn)入和離開關(guān)鍵區(qū)域四個(gè)函數(shù)。
2.關(guān)鍵段可以解決線程的互斥問(wèn)題,但因?yàn)榫哂小熬€程所有權(quán)”,所以無(wú)法解決同步問(wèn)題。
3.推薦關(guān)鍵段與旋轉(zhuǎn)鎖配合使用。
下一篇將介紹事件Event。
,參考:https://blog.csdn.net/morewindows/article/details/7442639