同步對象
/************************************************************************//* 同步對象(Mutex)互斥對象具有的機制:如果互斥對象沒有被任何線程擁有,那麼它是"標記的",如果被一個線程所擁有,那麼它是"未標誌的";任何一個線程獲得後,互斥對象就是"未標誌的", 其他線程不可以再擁有這個互斥對象。同一時刻,一個互斥對象最多隻能被一個線程擁有,從而實現"互斥"。概覽 同一時刻只有一個線程可以擁有Mutex對象 全域名稱的Mutex可以跨進程使用 在沒有線程擁有它時處於通知(置位)狀態 被線程擁有的時候處於非通知(非置位)狀態函數 建立一個Mutex同步對象 HANDLE CreateMutex( __in_opt LPSECURITY_ATTRIBUTES lpMutexAttributes,//不支援,設定為NULL __in BOOL bInitialOwner, //是否為建立該Mutex的線程所擁有 __in_opt LPCSTR lpName ); //可選,該Mutex的名字 釋放對Mutex的佔用 BOOL ReleaseMutex( //一個線程釋放了互斥對象後,如果其他線程在等待互斥對象置位,則等待的線程可以得到該互斥對象,等待函數返回,互斥對象被新的線程所擁有 __in HANDLE hMutex //Mutex的控制代碼 );*//************************************************************************//************************************************************************//* 同步對象(Semaphore)訊號量維護了一個計數器,計數器的值可以在0到指定的最大值之間。當一個線程完成了對訊號量的等待後,訊號量計數器值減少;當一個線程釋放訊號量是,訊號量計數器值增加。當計數器值達到零後,訊號量是"未標誌的",當計數器值大於零時,訊號量是“標誌的”。當計數器值降為到零時,任何線程都無法等待訊號量變為“標誌的”,因此訊號量對限制可訪問共用資料的線程數量很有用處。使用訊號量可以達到限制訪問共用資料的線程數量的功能。概覽 限制佔有共用資源的數量(如果一個Semaphore帶有計數n,這表示同時最多可以有n個線程佔有該Semaphore) 全域名稱的Semaphore可以跨進程使用 引用計數大於0時處於通知狀態 引用計數小於等於0時處於非通知狀態函數 建立一個Semaphore對象 HANDLE WINAPI CreateSemaphore( __in_opt LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, //不支援,設為NULL __in LONG lInitialCount, //初始計數值 __in LONG lMaximumCount, //最大支援的線程數,最大計數值 __in_opt LPCWSTR lpName ) //可選,semaphore的名字 釋放Semaphore BOOL ReleaseSemaphore( __in HANDLE hSemaphore, //要釋放的Semaphore控制代碼 __in LONG lReleaseCount, //釋放的引用個數,可以一次釋放多個計數 __out_opt LPLONG lpPreviousCount ) //返回釋放前的semaphore計數*//************************************************************************//************************************************************************//* 同步對象(Event)概覽 全域名稱的Event可以跨進程使用 事件發生時處於通知狀態 事件未發生時處於非通知狀態函數 建立同步對象Event HANDLE CreateEvent( __in_opt LPSECURITY_ATTRIBUTES lpEventAttributes, //不可用,設為NULL __in BOOL bManualReset, //是否需要人工重設,所謂重設是指將已標記的事件對象再重新設定為未標誌。如果為TRUE, //則需ResetEvent()來重設,如果為FALSE,那麼等待函數在等待到事件置位後,自動將事件重設。 __in BOOL bInitialState, //初始狀態,TRUE為通知狀態 __in_opt LPCWSTR lpName //可選,Event的名字 ) 把Event同步對象設定為通知狀態/未通知狀態 BOOL SetEvent( __in HANDLE hEvent ) //Event的控制代碼 BOOL ResetEvent( __in HANDLE hEvent )//Event的控制代碼,將事件重設為"未通知"狀態。如果事件時手工重設的,那麼需要使用此函數愛重設事件。*//************************************************************************//************************************************************************//* 同步(CriticalSection)概覽 允許多個線程共用訪問同一塊資料 使用互斥訪問保護資料 其他線程會block直到佔用者放棄臨界區 每個CriticalSection都是OS提供的一個資料結構,只能在同一個進程內部使用,比Mutex要高效函數 InitializeCriticalSection( __out LPCRITICAL_SECTION lpCriticalSection ); //分配CriticalSection結構 EnterCriticalSection( __inout LPCRITICAL_SECTION lpCriticalSection ); //在佔有CriticalSection的線程調用LeaveCriticalSection之前會阻塞 TryEnterCriticalSection( __inout LPCRITICAL_SECTION lpCriticalSection );//EnterCriticalSection的非阻塞版 LeaveCriticalSection( __inout LPCRITICAL_SECTION lpCriticalSection ); //釋放CriticalSection的所有權 DeleteCriticalSection( __inout LPCRITICAL_SECTION lpCriticalSection ); //釋放InitializeCriticalSection分配的資源*//************************************************************************/
Mutex執行個體
//執行個體 使用Mutex對象對共用的全域變數iData進行訪問#include <windows.h>#include <stdio.h>HANDLE hMutex;int iData=0;DWORD WINAPI ThreadProc1(LPVOID lParam){WaitForSingleObject(hMutex,INFINITE); //擷取Mutex對象for (int i=0;i<(int)lParam;i++) {iData++; //訪問共用資源printf("iData++ %d\n",iData);}ReleaseMutex(hMutex); //釋放同步對象return 0;}DWORD WINAPI ThreadProc2(LPVOID lParam){WaitForSingleObject(hMutex,INFINITE); //擷取Mutex對象for (int i=0;i<(int)lParam;i++){iData--; //訪問共用資源printf("iData-- %d\n",iData);}ReleaseMutex(hMutex); //釋放同步對象return 0;}void Init(){hMutex=CreateMutex(NULL,FALSE,NULL);CreateThread(NULL,0,ThreadProc1,(LPVOID)4,0,NULL);CreateThread(NULL,NULL,ThreadProc2,(LPVOID)5,NULL,NULL);}int main(){Init();system("pause");return 0;}
Event執行個體
//執行個體 使用Event對象對共用的全域變數進行訪問#include <windows.h>#include <stdio.h>HANDLE hEvent;int iData=0;DWORD WINAPI ThreadProc1(LPVOID lParam){WaitForSingleObject(hEvent,INFINITE); //等待事件發生for (int i=0;i<(int)lParam;i++){iData++; //訪問共用資源printf("iData++ %d\n",iData);}SetEvent(hEvent); //讓事件再次發生return 0;}DWORD WINAPI ThreadProc2(LPVOID lParam){WaitForSingleObject(hEvent,INFINITE); //等待事件發生for (int i=0;i<(int)lParam;i++){iData--; //訪問共用資源printf("iData-- %d\n",iData);}SetEvent(hEvent); //讓事件再次發生return 0;}VOID Init(){hEvent=CreateEvent(NULL,FALSE,TRUE,NULL);CreateThread(NULL,NULL,ThreadProc1,(LPVOID)4,NULL,NULL);CreateThread(NULL,NULL,ThreadProc2,(LPVOID)5,NULL,NULL);}int main(){Init(); system("pause");return 0;}
CriticalSection執行個體
//執行個體 使用CriticalSection對象對共用的全域變數進行訪問#include <windows.h>#include <stdio.h>CRITICAL_SECTION cs;int iData=0;DWORD WINAPI ThreadProc1(LPVOID lParam){EnterCriticalSection(&cs); //進入臨界區for (int i=0;i<(int)lParam;i++){iData++; //訪問共用資料printf("iData++ %d\n",iData);}LeaveCriticalSection(&cs); //離開臨界區return 0;}DWORD WINAPI ThreadProc2(LPVOID lParam){EnterCriticalSection(&cs); //進入臨界區for (int i=0;i<(int)lParam;i++){iData--; //訪問共用資料printf("iData-- %d\n",iData);}LeaveCriticalSection(&cs); //離開臨界區return 0;}void Init(){InitializeCriticalSection(&cs);CreateThread(NULL,NULL,ThreadProc1,(LPVOID)4,NULL,NULL);CreateThread(NULL,NULL,ThreadProc2,(LPVOID)5,NULL,NULL);}int main(){Init();system("pause");return 0;}
上面3個執行個體的結果都是: