前言:編程
具體的可等待的內核對象有:數組
進程,線程,做業,文件以及控制檯的標準輸入流/輸出流/錯誤流,事件,可等待的計時器,信號量,互斥量。函數
等待函數:測試
DWORD WaitForSingleObject( HANDLE hObject,//用來標識要等待的內核對象 DWORD dwMilliseconds);//等待的時間 DWORD WaitForMultipleObjects( DWORD dwCount,//函數檢查的內核對象的數量(最大爲MAXIMUM_WAIT_OBJECTS) CONST HANDLE* phObjects,//指向一個內核對象句柄的數組 BOOL bWaitAll,//是否等待所有對象都觸發 DWORD dwMilliseconds);//等待時間
等待成功引發的反作用:(Windows核心編程)spa
當等待函數發現對象已經被觸發,則稱爲一個成功的調用,當調用後,對象的狀態發生了變化,則稱之爲等待成功引發的反作用。操作系統
正文:線程
1.事件內核對象(Event)code
事件包含一個引用計數,一個用來表示事件是自動重置事件仍是手動重置事件的布爾值,以及另外一個用來表示事件有沒有被觸發的布爾值。對象
HANDLE CreateEvent( PSECURITY_ATTRIBUTES psa, BOOL bManualReset,//TRUE表示手工重置,FALSE表示自動重置 BOOL bInitialState,//TRUE表示觸發狀態,FALSE表示未觸發狀態 PCTSTR pszName); HANDLE CreateEventEx( PSECURITY_ATTRIBUTES psa, PCTSTR pszName, DWORD dwFlags,//CREATE_EVENT_INITIAL_SET設置了則初始化爲觸發狀態 //,CREATE_EVENT_MANUAL_RESET設置了則建立一個手工重置事件 DWORD dwDesiredAccess);//指定在建立事件時返回的句柄對事件有何種訪問權限 HANDLE OpenEvent( DWORD dwDesiredAccess, BOOL bInherit, PCTSTR pszName); BOOL SetEvent(HANDLE hEvent);//觸發事件 BOOL ResetEvent(HANDLE hEvent);//把事件設爲未觸發狀態 BOOL PulseEvent(HANDLE hEvent);//先觸發事件後當即恢復到未觸發狀態
當一個手工重置事件被觸發的時候,正在等待該事件的全部線程都將變成可調度狀態。當一個自動重置事件被觸發的時候,只有一個正在等待該事件的線程會變成可調度狀態。blog
2.可等待的計時器內核對象(Waitable Timer)
能夠在某個指定的時間觸發,或每隔一段時間觸發一次。
HANDLE CreateWaitableTimer( PSECURITY_ATTRIBUTES psa, BOOL bManualReset, PCTSTR pszName); HANDLE OpenWaitableTimer( DWORD dwDesiredAccess, BOOL bInheritHandle, PCTSTR pszName); BOOL SetWaitableTimer( HANDLE hTimer, const LARGE_INTEGER* pDueTime,//表示第一次觸發時間在何時 LONG lPeriod,//在第一次觸發以後,計時器應該以怎麼樣的頻率觸發 PTIMERAPCROUTINE pfnCompletionRoutine,//APC PVOID pvArgToCompletionRoutine,//APC參數 BOOL bResume); BOOL CancelWaitableTimer(HANDLE hTimer);//取消計時器
設置可等待計時器時候的pDueTime參數是LARGE_INTEGER*類型的,須要將SYSTEMTIME類型的時間利用SystemTimeToFileTime()轉換位FileTime,再將FileTime的成員複製到LARGE_INTEGER結構成員中,而後再將LARGE_INTEGER的地址傳給pDueTime。
3.信號量內核對象(Semaphore)
包含一個使用計數,還有一個最大資源計數,一個當前資源計數。
信號量的使用規則以下:
1若是當前的資源計數大於0,那麼信號量處於觸發狀態;
2若是當前的資源計數等於0,那麼信號量處於未觸發狀態;
3系統絕對不會讓當前資源計數變爲負數
4當前資源計數絕對不會大於最大資源計數
HANDLE CreateSemaphore( PSECURITY_ATTRIBUTE psa, LONG lInitialCount, LONG lMaximumCount, PCTSTR pszName); HANDLE CreateSemaphoreEx( PSECURITY_ATTRIBUTES psa, LONG lInitialCount, LONG lMaximumCount, PCTSTR pszName, DWORD dwFlags,//設爲0,系統保留 DWORD dwDesiredAccess);
BOOL ReleaseSemaphore(
HANDLE hSemaphore,
LONG lReleaseCount,
PLONG plPreviousCount);//遞增信號量的當前資源計數
信號量以原子方式來執行測試和設置操做,當咱們向信號量請求一個資源的時候,操做系統會檢查資源是否可用,並將可用資源的數量遞減,整個過程不會被別的線程打斷。
4.互斥量內核對象(Mutex)
互斥量對象包含一個使用計數、線程ID以及一個遞歸計數。線程ID用來標識當前佔用這個互斥量的是系統中哪一個線程,遞歸計數表示這個線程佔用該互斥量的次數。
互斥量的使用規則:
1若是線程ID爲0(無效),那麼該互斥量不爲任何線程所佔用,他處於觸發狀態。
2若是線程ID爲非0值,那麼有一個線程已經佔用了該互斥量,他處於未觸發狀態
3與全部其餘內核對象不一樣,操做系統對互斥量進行了特殊處理,容許它們違反一些常規的規則(下面說)
HANDLE CreateMutex( PSECURITY_ATTRIBUTES pas, BOOL bInitialOwner,//控制互斥量的初始狀態,若是傳FALSE,
//那麼互斥量對象的線程ID和遞歸計數都將被設爲0(觸發狀態),
//傳TRUE,線程ID爲調用線程的線程ID,遞歸計數將被設爲1(未觸發狀態) PCTSTR pszName); HANDLE CreateMutexEx( PSECURITY_ATTRIBUTES psa, PCTSTR pszName, DWORD dwFlags, DWORD dwDesiredAccess); HANDLE OpenMutex( DWORD dwDesiredAccess, BOOL bInheritHandle, PCTSTR pszName); BOOL ReleaseMutex(HANDLE hMutex);//釋放互斥量,遞歸計數減1
使用方法:
爲了得到對被保護資源的訪問權,線程要調用一個等待函數並傳入互斥量的句柄。在內部,等待函數會檢查線程ID是否爲0.若是爲0,那麼函數會把線程ID設爲調用線程的線程ID,把遞歸計數設爲1,而後讓調用線程繼續運行。(至關於關鍵段的EnterCriticalSection())。
若是等待函數檢測到線程ID不爲0,那麼調用線程將進入等待狀態。當另外一個線程將互斥量的線程ID設爲0的時候,系統會記得有一個線程正在等待,因而它把線程ID設爲正在等待的那個線程的線程ID,把遞歸計數設爲1,使正在等待的線程變爲可調度狀態。
上面所說的互斥量的一切都與其餘的內核對象同樣,可是互斥量有一些本身的特性:
上面說的違反一些常規規則即是:若是等待函數檢測到線程ID不爲0可是和目前的調用線程的線程ID相等,那麼系統會讓線程保持可調度狀態——即便該互斥量還沒有觸發,而後遞歸計數加1,使遞歸計數大於1的惟一途徑是利用這個例外,讓線程屢次等待同一個互斥量。
當釋放互斥量時ReleaseMutex也會檢查調用線程的線程ID與互斥量內部的線程ID是否一致,若是一致,遞歸計數會遞減;若是不一致,那麼將返回FALSE,調用GetLastError會返回ERROR_NOT_OWNER。
更多的等待函數:
//等待hProcess標識的進程,直到建立應用程序第一個窗口的線程沒有待處理的輸入爲止。 DWORD WaitForInputIdle( HANDLE hProcess, DWORD dwMilliseconds); //不只內核對象被觸發的是時候調用線程會變成可調度狀態,並且當窗口信息須要被派送到一個 //由調用線程建立的窗口時,他們也會變成可調度狀態。 DWORD MsgWaitForMultipleObjects( DWORD dwCount, PHANDLE phObjects, BOOL bWaitAll, DWORD dwMilliseconds, DWORD dwWakeMask); DWORD MsgWaitForMultipleObjectsEx( DWORD dwCount, PHANDLE phObjects, DWORD dwMilliseconds, DWORD dwWakeMask, DWORD dwFlags); BOOL WaitForDebugEvent( PDEBUG_EVENT pde, DWORD dwMilliseconds); //原子操做來觸發一個內核對象並等待另外一個內核對象 DWORD SignalObjectAndWait( HANDLE hObjectToSignal,//只能是互斥量,事件,信號量內核對象 HANDLE hObjectToWaitOn,//可等待的內核對象便可 DWORD dwMilliseconds, BOOL bAlertable);