標籤:alt pac null ima adf ref code 判斷 div
一、關鍵段CS 和 互斥量Mutex 的相同點:都有線程擁有權
關鍵段和互斥量都有線程擁有權,即可以被一個線程擁有。在 前面講關鍵段CS的文章中有說到,關鍵段結構體的第四個參數儲存著擁有該關鍵段的線程的控制代碼,具體如下:
typedef struct _RTL_CRITICAL_SECTION { PRTL_CRITICAL_SECTION_DEBUG DebugInfo; // // The following three fields control entering and exiting the critical // section for the resource // LONG LockCount; LONG RecursionCount; HANDLE OwningThread; // from the thread‘s ClientId->UniqueThread HANDLE LockSemaphore; ULONG_PTR SpinCount; // force size on 64-bit systems when packed} RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;
第一個參數:PRTL_CRITICAL_SECTION_DEBUG DebugInfo; 調試的時候用的,先不做介紹。
第二個參數:LONG LockCount; 初始化為-1,n表示有n個線程在等待。
第三個參數:LONG RecursionCount; 表示該關鍵段的擁有線程對此資源獲得關鍵段次數,初為0。
第四個參數:HANDLE OwningThread; 即擁有該關鍵段的線程控制代碼
第五個參數:HANDLE LockSemaphore; 實際上是一個自複位事件。
第六個參數:ULONG_PTR SpinCount; 旋轉鎖的設定,用於多處理器。
現在我們來分析以下程式:
#include<iostream>#include <windows.h>using namespace std;const unsigned int THREAD_NUM = 10;unsigned int g_Count = 0;CRITICAL_SECTION cs;DWORD WINAPI ThreadFunc(LPVOID);int main(){ InitializeCriticalSection(&cs); HANDLE hThread[THREAD_NUM]; for (int i = 0; i < THREAD_NUM; i++) { EnterCriticalSection(&cs); // 進入關鍵段,執行這一句時主線程就獲得了這個關鍵段的擁有權。 hThread[i] = CreateThread(NULL, 0, ThreadFunc,0, 0, NULL); } WaitForMultipleObjects(THREAD_NUM, hThread,true,INFINITE); cout << THREAD_NUM << " 個線程全部返回" << endl; return 0;}DWORD WINAPI ThreadFunc(LPVOID p){ LeaveCriticalSection(&cs); // 離開關鍵段 Sleep(50); EnterCriticalSection(&cs); // 進入關鍵段 cout<<"g_Count 的值為:"<<g_Count++<<endl; LeaveCriticalSection(&cs); // 離開關鍵段 Sleep(50); return 0;}
如所示加上兩個斷點進行調試,正常來說程式應該是依次經過兩個斷點,但是調試時我們發現,程式會多次重複進入第一個斷點,這是因為執行到第一個斷點式時主線程就獲得了這個關鍵段的擁有權。
同樣地,Mutex也擁有線程所有權,需要瞭解互斥量看這裡。和上面一樣,我們寫這樣一個程式
#include <iostream>#include <windows.h>using namespace std;const unsigned int THREAD_NUM = 10;unsigned int g_Count = 0;CRITICAL_SECTION cs;HANDLE g_Mutex;DWORD WINAPI ThreadFunc(LPVOID);int main(){ InitializeCriticalSection(&cs); g_Mutex = CreateMutex(NULL, false, NULL); //初始化互斥量為觸發狀態 HANDLE hTread[THREAD_NUM]; for (int i = 0; i < THREAD_NUM;i++) { WaitForSingleObject(g_Mutex, INFINITE); //等待互斥量觸發 hTread[i] = CreateThread(NULL, 0, ThreadFunc, 0, 0, NULL); } WaitForMultipleObjects(THREAD_NUM, hTread, true, INFINITE); cout << THREAD_NUM << " 個線程全部返回" << endl; return 0;}DWORD WINAPI ThreadFunc(LPVOID p){ //ReleaseMutex(g_Mutex); Sleep(50); EnterCriticalSection(&cs); // 進入關鍵段 cout << "g_Count 的值為:" << g_Count++ << endl; LeaveCriticalSection(&cs); // 離開關鍵段 Sleep(50); ReleaseMutex(g_Mutex); //觸發互斥量 return 0;}
同樣地,我們在程式中下兩個斷點,同樣地程式會不經過第二個斷點,而重複經過第一個斷點。
前面關鍵段和互斥量兩篇文章我們說了關鍵段CS和互斥量Mutex不能做到線程同步,只能做到臨界資源互斥訪問,就是因為,他它們都有線程擁有權的原因。
二、關鍵段CS 和 互斥量Mutex 的不同點:由於互斥量常用於多進程之間的線程互斥,所以它比關鍵段還多一個很有用的特性——“遺棄”情況的處理。
看下面的程式:
程式一:
#include <stdio.h>#include <windows.h>const char MutexName[] = "MyMutex"; //互斥量名字int main(){ HANDLE hMutex = CreateMutex(NULL, TRUE, MutexName); //建立互斥量並初始化為未觸發狀態 printf("互斥量已經建立,按任意鍵觸發\n"); getch(); exit(0); //在互斥量觸發前退出程式。 //ReleaseMutex(hMutex); // 觸發互斥量 printf("互斥量已經被觸發\n"); CloseHandle(hMutex); return 0;}
程式二:
#include <stdio.h>#include <windows.h>const char MutexName[] = "MyMutex"; //互斥量名字int main(){ HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, TRUE, MutexName); //開啟互斥量 if (NULL != hMutex) { printf("開啟互斥量成功,等待互斥量被觸發\n"); DWORD mRes = WaitForSingleObject(hMutex, INFINITE); // 等待互斥量被觸發 if (WAIT_ABANDONED == mRes) //判斷互斥量是否被遺棄 { printf("互斥量被遺棄。\n"); } //printf("互斥量已經被觸發\n"); } else { printf("互斥量開啟失敗。\n"); } CloseHandle(hMutex); return 0;}
先運行,程式一,然後運行程式二,如所示。
此時在,程式一中按任意鍵,使程式一在互斥量未觸發之前退出,程式二輸出如下:
這篇是邊學邊寫出來的可能有不正確的地方,歡迎指出!!!!!
windows多線程(六) 互斥量Mutex與關鍵段CriticalSection比較