內核對象進行線程同步

前言:編程

具體的可等待的內核對象有:數組

  進程,線程,做業,文件以及控制檯的標準輸入流/輸出流/錯誤流,事件,可等待的計時器,信號量,互斥量。函數

等待函數:測試

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);
相關文章
相關標籤/搜索