日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > windows >内容正文

windows

线程与内核对象的同步——Windows核心编程学习手札之九

發(fā)布時(shí)間:2025/4/16 windows 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 线程与内核对象的同步——Windows核心编程学习手札之九 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

線(xiàn)程與內(nèi)核對(duì)象的同步

——Windows核心編程學(xué)習(xí)手札之九

用戶(hù)方式下的線(xiàn)程同步機(jī)制具有速度快的特點(diǎn),但有其局限性,對(duì)于許多應(yīng)用程序來(lái)說(shuō),并不合適。例如,互鎖函數(shù)家族只能在單值上運(yùn)行,根本無(wú)法使線(xiàn)程進(jìn)入等待狀態(tài);關(guān)鍵代碼可以使線(xiàn)程進(jìn)入等待狀態(tài),但只能用關(guān)鍵代碼段對(duì)單個(gè)進(jìn)程中的線(xiàn)程實(shí)施同步,使用關(guān)鍵代碼段也容易陷入死鎖,因?yàn)樵诘却M(jìn)入關(guān)鍵代碼段時(shí)無(wú)法設(shè)定超時(shí)值。內(nèi)核方式下的線(xiàn)程同步機(jī)制適應(yīng)性要優(yōu)于用戶(hù)方式下的機(jī)制,唯一不足的是內(nèi)核對(duì)象機(jī)制的速度比較慢。內(nèi)核對(duì)象機(jī)制下線(xiàn)程必須從用戶(hù)方式轉(zhuǎn)為內(nèi)核方式,這個(gè)轉(zhuǎn)換需要很大代價(jià):往返一次需要占用X86平臺(tái)上大約1000個(gè)CPU周期,當(dāng)然還不包括執(zhí)行內(nèi)核方式代碼,即實(shí)現(xiàn)線(xiàn)程調(diào)用的函數(shù)的代碼所需時(shí)間。

對(duì)于線(xiàn)程同步來(lái)說(shuō),內(nèi)核對(duì)象中的每種對(duì)象(包括進(jìn)程、線(xiàn)程、作業(yè))都可以說(shuō)是處于已通知或未通知的狀態(tài)之中,這種狀態(tài)的切換是由Microsoft為每個(gè)對(duì)象建立的一套規(guī)則來(lái)決定。例如,進(jìn)程內(nèi)核對(duì)象總是未通知的狀態(tài)中創(chuàng)建的,當(dāng)進(jìn)程終止運(yùn)行時(shí),操作系統(tǒng)自動(dòng)使該進(jìn)程的內(nèi)核對(duì)象處于已通知狀態(tài),一旦進(jìn)程內(nèi)核對(duì)象得到通知,它將永遠(yuǎn)保持這種狀態(tài),它的狀態(tài)永遠(yuǎn)不會(huì)改為未通知狀態(tài)。當(dāng)進(jìn)程正在運(yùn)行時(shí),進(jìn)程內(nèi)核對(duì)象處于未通知狀態(tài),當(dāng)進(jìn)程終止運(yùn)行時(shí),就變?yōu)橐淹ㄖ獱顟B(tài)。線(xiàn)程的內(nèi)核對(duì)象如是,因此可以將相同方法應(yīng)用于程序。下面的內(nèi)核對(duì)象可以處于已通知狀態(tài)或未通知狀態(tài):1)進(jìn)程;2)文件修改通知;3)線(xiàn)程;4)事件;5)作業(yè);6)可等待定時(shí)器;7)文件;8)信標(biāo);9)控制臺(tái)輸入;10)互斥對(duì)象。線(xiàn)程可以使自己進(jìn)入等待狀態(tài),直到一個(gè)對(duì)象變?yōu)橐淹ㄖ獱顟B(tài)。注意,用于控制每個(gè)對(duì)象的已通知/未通知狀態(tài)的規(guī)則要根據(jù)對(duì)象類(lèi)型而定。Windows提供專(zhuān)門(mén)實(shí)現(xiàn)線(xiàn)程同步的各種內(nèi)核對(duì)象,如事件、等待計(jì)數(shù)器、信標(biāo)和互斥對(duì)象。

等待函數(shù)可使線(xiàn)程資源進(jìn)入等待狀態(tài),直到一個(gè)特定的內(nèi)核對(duì)象變?yōu)橐淹ㄖ獱顟B(tài)為止,這些等待函數(shù)中最常用的是WaitForSingleObject

DWORD WaitForSingleObject(

?????????????????????????????????? HANDLE hObject,

?????????????????????????????????? DWORD dwMillisecondes)

當(dāng)線(xiàn)程調(diào)用該函數(shù)時(shí),第一個(gè)參數(shù)hObject標(biāo)識(shí)一個(gè)能夠支持被通知/未通知的內(nèi)核對(duì)象,第二個(gè)參數(shù)dwMilliseconds運(yùn)行線(xiàn)程設(shè)置等待的時(shí)間長(zhǎng)度。

函數(shù)WaitForMultipleObjects允許調(diào)用線(xiàn)程同時(shí)查看若干個(gè)內(nèi)核對(duì)象的已通知狀態(tài):

DWORD WaitForMultipleObjects(

?????????????????????????????????? DWORD dwCount,

?????????????????????????????????? CONST HANDLE *phObjects,

?????????????????????????????????? BOOL fWailAll,

?????????????????????????????????? DWORD dwMilliseconds)

該函數(shù)的參數(shù)dwCount用于指明想要讓函數(shù)查看的內(nèi)核對(duì)象的數(shù)量,這個(gè)值必須在1MAXIMUN_WAIT_OBJECTS(在Windows頭文件中定義為64)之間;參數(shù)phObjects參數(shù)是指向內(nèi)核對(duì)象句柄的數(shù)組的指針。參數(shù)fWaitAll告訴函數(shù)是在指定內(nèi)核對(duì)象中任何一個(gè)變?yōu)橐淹ㄖ獱顟B(tài)還是在所有指定的內(nèi)核對(duì)象都變?yōu)橐淹ㄖ獱顟B(tài)下線(xiàn)程可運(yùn)行,如fWaitAll傳遞了TRUE,那么在所有對(duì)象變?yōu)橐淹ㄖ?#xff0c;該函數(shù)將不運(yùn)行調(diào)用線(xiàn)程運(yùn)行;dwMillisecondsWaitForSingleObject作用一樣,用于設(shè)置等待時(shí)長(zhǎng)。

事件內(nèi)核對(duì)象是最基本的對(duì)象,包含一個(gè)使用計(jì)數(shù)(與所有內(nèi)核對(duì)象一樣)、一個(gè)用于指明該事件是個(gè)自動(dòng)重置的事件還是一個(gè)人工重置的事件的布爾值、用于指明該事件處于已通知狀態(tài)還是未通知狀態(tài)的布爾值。事件能夠通知一個(gè)操作已經(jīng)完成,有兩種不同類(lèi)型的事件對(duì)象,一種是人工重置的事件,另一種是自動(dòng)重置的事件。當(dāng)人工重置的事件得到通知時(shí),等待該事件的所有線(xiàn)程均變?yōu)榭烧{(diào)度的線(xiàn)程;當(dāng)一個(gè)自動(dòng)重置的事件得到通知時(shí),等待該事件的線(xiàn)程中只有一個(gè)線(xiàn)程變?yōu)榭烧{(diào)度的線(xiàn)程。當(dāng)一個(gè)線(xiàn)程執(zhí)行初始化操作,然后通知另一個(gè)線(xiàn)程執(zhí)行剩余的操作時(shí),事件使用得最多。事件初始化為未通知狀態(tài),在該線(xiàn)程完成它的初始化操作后,它將事件設(shè)置為已通知狀態(tài),這時(shí),等待該事件的另一個(gè)線(xiàn)程發(fā)現(xiàn)該事件已經(jīng)得到通知,此線(xiàn)程序就變成可調(diào)度線(xiàn)程。

創(chuàng)建事件內(nèi)核對(duì)象:

HANDLE CreateEvent(

?????????????????????????????????? PSECURITY_ATTRIBUTES psa,

?????????????????????????????????? BOOL fManualReset,

?????????????????????????????????? BOOL fInitialState,

?????????????????????????????????? PCTSTR pszName);

其中,fManualReset參數(shù)是布爾值,告訴系統(tǒng)創(chuàng)建人工重置的事件(TRUE)或是自動(dòng)重置事件(FALSE);fInitialState參數(shù)用于指明該事件是要初始化為已通知狀態(tài)(TRUE)還是未通知狀態(tài)(FALSE);當(dāng)系統(tǒng)創(chuàng)建事件對(duì)象后,createEvent就將與進(jìn)程相關(guān)的句柄返回給事件對(duì)象,其他進(jìn)程中的線(xiàn)程可以獲得對(duì)該對(duì)象的訪(fǎng)問(wèn)權(quán),方法是使用在pszName參數(shù)中傳遞的相同值,使用繼承性,使用DuplicateHandle函數(shù)等來(lái)調(diào)用CreateEvent,或者調(diào)用OpenEvent,在pszName參數(shù)中設(shè)定一個(gè)與調(diào)用createEvent時(shí)設(shè)定的名字相匹配的名字:

HANDLE OpenEvent(

??????????????????????????? DWORD fdwAccess,

??????????????????????????? BOOL fInherit,

??????????????????????????? PCTSTR pszName);

與其他內(nèi)核對(duì)象一樣,當(dāng)不再需要事件內(nèi)核對(duì)象時(shí),應(yīng)調(diào)用CloseHandle函數(shù)。

一旦事件已經(jīng)創(chuàng)建,就可以直接控制它的狀態(tài),當(dāng)調(diào)用SetEvent時(shí),可以將事件改為已通知狀態(tài):BOOL SetEvent(HANDLE hEvent);當(dāng)調(diào)用ResetEvent(HANDLE hEvent)函數(shù)時(shí),就可以將該事件改為未通知狀態(tài)。函數(shù)BOOL PulseEvent(HANDLE hEvent)使得事件變?yōu)橐淹ㄖ獱顟B(tài),然后立即變?yōu)槲赐ㄖ獱顟B(tài),如調(diào)用SetEvent后又立即調(diào)用ResetEvent函數(shù)。

下面的代碼例子說(shuō)明了自動(dòng)重置事件的用法,具體是實(shí)現(xiàn)了由主線(xiàn)程向子線(xiàn)程發(fā)起請(qǐng)求時(shí)設(shè)置事件未通知狀態(tài),子線(xiàn)程響應(yīng)主線(xiàn)程序請(qǐng)求:

#include <process.h>

//this event is signaled when the client has a request for server

HANDLE g_hEventRequestSubmitted;

//this event is signaled when the server has a result for the client

HANDLE g_hEventResultReturned;

//the buffer shared between the client an server threads

TCHAR g_szSharedRequestAndResultBuffer[1024];

//server thread to terminate cleanly

TCHAR g_szServerShutdown[]=TEXT("Server Shutdown");

?

//this is the code executed by the server thread

UINT WINAPI ServerThread(PVOID pvParam)

{

?????? //assume that the server thread is to run forever

?????? BOOL fShutdown=FALSE;

?????? while(!fShutdown)

?????? {

????????????? //wait for the client to submit a request

????????????? WaitForSingleObject(g_hEventRequestSubmitted,INFINITE);

????????????? //check to see if the client wants the server to terminate

????????????? fShutdown=(lstrcmpi(g_szSharedRequestAndResultBuffer,g_szServerShutdown)==0);

????????????? if(!fShutdown)

????????????? {

???????????????????? //process the client's requet(reverse the string)

???????????????????? _tcsrev(g_szSharedRequestAndResultBuffer);

????????????? }

?

????????????? //let the client process the request's result

????????????? SetEvent(g_hEventResultReturned);

?????? }

?????? return 0;

}

?

void CEventDemoDlg::OnOK()

{

?????? // TODO: Add extra validation here

?????? //create & initialize the two nonsignaled ,auto-reset events

?????? g_hEventRequestSubmitted=CreateEvent(NULL,FALSE,FALSE,NULL);

?????? g_hEventResultReturned=CreateEvent(NULL,FALSE,FALSE,NULL);

?

?????? //spawn the server thread

?????? UINT dwThreadID;

?????? HANDLE hThreadServer=(HANDLE)_beginthreadex(NULL,0,ServerThread,NULL,0,&dwThreadID);

?

?????? CString strReq;

?????? GetDlgItemText(IDC_EditReq,strReq);

?????? strcpy(g_szSharedRequestAndResultBuffer,strReq);

?

?????? //let the server thread know that a request is ready in the buffer

?????? SetEvent(g_hEventRequestSubmitted);

?

?????? //wait for the server to process the request and give us the result

?????? WaitForSingleObject(g_hEventResultReturned,INFINITE);

?????? //let the user know the result

?????? strReq.Format(_T("%s"), g_szSharedRequestAndResultBuffer);

?????? SetDlgItemText(IDC_EditRes,strReq);

?

?

?????? //end

?????? lstrcpy(g_szSharedRequestAndResultBuffer,g_szServerShutdown);

?????? SetEvent(g_hEventRequestSubmitted);

?????? //wait for the server thread to acknowledge the shutdown and wait for the server thread to fully terminate

?????? HANDLE h[2];

?????? h[0]=g_hEventResultReturned;

?????? h[1]=hThreadServer;

?????? WaitForMultipleObjects(2,h,TRUE,INFINITE);

?????? //properly clean up everything

?????? CloseHandle(hThreadServer);

?????? CloseHandle(g_hEventRequestSubmitted);

?????? CloseHandle(g_hEventResultReturned);

?????? //close the application

//???? CDialog::OnOK();

?????? AfxMessageBox("close the application");

}

void CEventDemoDlg::OnOK() VC6.0Dialog工程的一個(gè)按鈕函數(shù),在這里具體實(shí)現(xiàn)了事件的狀態(tài)變化來(lái)同步線(xiàn)程的運(yùn)行。

等待定時(shí)器內(nèi)核對(duì)象是在某個(gè)時(shí)間或按規(guī)定的間隔時(shí)間發(fā)出自己的信號(hào)來(lái)通知,用在某個(gè)時(shí)間執(zhí)行某個(gè)操作,其函數(shù)是:

HANDLE CreateWaitableTimer(

??????????????????????????? PSECURITY_ATTRIBUTES psa,

??????????????????????????? BOOL fManualReset,

??????????????????????????? PCTSTR pszName);

進(jìn)程可以獲得與自己相關(guān)的現(xiàn)有等待定時(shí)器的句柄,通過(guò)函數(shù):

HANDLE OpenWaitableTimer(

??????????????????????????? DWORD dwDesiredAccess,

??????????????????????????? BOOL bInheritHandle,

??????????????????????????? PCTSTR pszName);

與事件內(nèi)核對(duì)象一樣,fManualReset參數(shù)用于指明人工重置的定時(shí)器或自動(dòng)重置的定時(shí)器。當(dāng)發(fā)出人工重置的定時(shí)器信號(hào)通知時(shí),等待該定時(shí)器的所有線(xiàn)程均變?yōu)榭烧{(diào)度的線(xiàn)程,當(dāng)發(fā)出自動(dòng)重置的定時(shí)器信號(hào)通知時(shí),只有一個(gè)等待的線(xiàn)程變?yōu)榭烧{(diào)度線(xiàn)程。

等待定時(shí)器總是在未通知狀態(tài)中創(chuàng)建,必須調(diào)用SetWaitableTimer函數(shù)來(lái)告訴定時(shí)器使其變?yōu)橐淹ㄖ獱顟B(tài):

BOOL SetWaitableTimer(

??????????????????????????? HANDLE hTimer,

??????????????????????????? Const LARGE_INTEGER *pDueTime,

??????????????????????????? LONG lPeriod,

??????????????????????????? PTIMERAPCROUTINE pfnCompletionRoutine,

??????????????????????????? PVOID pvArgToCompletionRoutine,

??????????????????????????? BOOL fResume);

其中,參數(shù)hTimer用于指明所設(shè)置的定時(shí)器;PDueTimelPeriod兩個(gè)參數(shù)是一同使用的,PDueTime指明定時(shí)器何時(shí)應(yīng)第一次報(bào)時(shí),而lPeriod參數(shù)則指明此后定時(shí)器應(yīng)間隔多長(zhǎng)時(shí)間報(bào)時(shí)一次,下面代碼用于將定時(shí)器的第一次報(bào)時(shí)設(shè)置在200918的下午一點(diǎn)鐘,然后每隔6小時(shí)報(bào)時(shí)一次:

//Declare our local variables.

HANDLE hTimer;

SYSTEMTIME st;

FILETIME ftLocal,ftUTC;

LARGE_INTEGER liUTC;

//create an auto-reset timer.

hTimer=CreateWaitableTimer(NULL,FALSE,NULL);

//first signaling is at January 8, 2009 at 1:00P.M. (local time).

st.wYear=2009;

st.wMonth=1;

st.wDayofWeek=0;

st.wDay=8;

st.wHour=13;

st.wMinute=0;

st.wSeconde=0;

st.wMilliseconds=0;

SystemTimeToFileTime(&st,&ftLocal);

//convert local time to UTC time.

LocalFileTimeToFileTime(&ftLocal,&ftUTC);

//convert FILETIME to LARGE_INTEGER because of different alignment.

liUTC.LowPart=ftUTC.dwLowDateTime;

liUIC.HighPart=ftUTC.dwHighDateTime;

//set the timer.

SetWaitableTimer(hTimer,&liUTC,6*60*60*1000,NULL,NULL,FALSE);

……

首先對(duì)SYSTEMTIME結(jié)構(gòu)進(jìn)行初始化,該結(jié)果用于指明定時(shí)器何時(shí)第一次報(bào)時(shí)(發(fā)出信號(hào)通知)。

信標(biāo)內(nèi)核對(duì)象用于對(duì)資源進(jìn)行計(jì)數(shù),與所有內(nèi)核對(duì)象一樣,包含一個(gè)使用數(shù)量,但也包含另外兩個(gè)帶符號(hào)的32位值,一個(gè)是最大資源數(shù)量,一個(gè)是當(dāng)前資源數(shù)量,最大資源數(shù)量用于標(biāo)識(shí)信標(biāo)能夠控制的資源的最大數(shù)量,而當(dāng)前資源數(shù)量則用于標(biāo)識(shí)當(dāng)前可以使用的資源的數(shù)量。信標(biāo)的使用規(guī)則是:1)如果當(dāng)前資源的數(shù)量大于0,則發(fā)出信標(biāo)信號(hào);2)如果當(dāng)前資源數(shù)量是0,則不發(fā)出信標(biāo)信號(hào);3)系統(tǒng)決不允許當(dāng)前資源的數(shù)量為負(fù)值;4)當(dāng)前資源數(shù)量決不能大于最大資源數(shù)量。當(dāng)使用信標(biāo)時(shí),不要將信標(biāo)對(duì)象的使用數(shù)量和它的當(dāng)前資源數(shù)量混為一談。創(chuàng)建信標(biāo)內(nèi)核對(duì)象的函數(shù)是:

HANDLE CreateSemaphore(

?????????????????????????????????? PSECURITY_ATTRIBUTE psa,

?????????????????????????????????? LONG lInitialCount,

?????????????????????????????????? LONG lMaximumCount,

?????????????????????????????????? PCTSTR pszName);

通過(guò)函數(shù)OpenSemaphore函數(shù),其他進(jìn)程可以獲得現(xiàn)有信標(biāo)有關(guān)的句柄:

HANDLE OpenSemaphore(

?????????????????????????????????? DWORD fdwAccess,

?????????????????????????????????? BOOL bInheritHandle,

?????????????????????????????????? PCTSTR pszName);

lMaximumCount參數(shù)用于告訴系統(tǒng),應(yīng)用程序處理的最大資源數(shù)量是多少,該參數(shù)是帶符號(hào)的32位值,因此最多可以擁有2147483647個(gè)資源。lInitialCount參數(shù)用于指明開(kāi)始時(shí)(當(dāng)前)這些資源有多少可供使用。信標(biāo)能以原子操作方式執(zhí)行測(cè)試和設(shè)置操作,也就是說(shuō),當(dāng)向信標(biāo)申請(qǐng)一個(gè)資源時(shí),操作系統(tǒng)就要檢查是否有這個(gè)資源可供使用,同時(shí)將可用資源的數(shù)量遞減,而不讓另一個(gè)線(xiàn)程加以干擾,只有當(dāng)資源數(shù)量遞減后,系統(tǒng)才允許另一個(gè)線(xiàn)程申請(qǐng)對(duì)資源的訪(fǎng)問(wèn)權(quán)。通過(guò)調(diào)用ReleaseSemaphore函數(shù),線(xiàn)程能夠?qū)π艠?biāo)的當(dāng)前資源數(shù)量進(jìn)行遞增:

BOOL ReleaseSemaphore(

?????????????????????????????????? HANDLE hsem,

?????????????????????????????????? LONG lReleaseCount,

?????????????????????????????????? PLONG plPreviousCount);

該函數(shù)將lReleaseCount中的值添加給信標(biāo)的當(dāng)前資源數(shù)量。

互斥對(duì)象(mutex)內(nèi)核對(duì)象能夠確保線(xiàn)程擁有對(duì)單個(gè)資源的互斥訪(fǎng)問(wèn)權(quán),包含一個(gè)使用數(shù)量,一個(gè)線(xiàn)程ID和一個(gè)遞歸計(jì)數(shù)器,互斥對(duì)象的行為特性和關(guān)鍵代碼段相同,但是互斥對(duì)象屬于內(nèi)核對(duì)象,而關(guān)鍵代碼段則屬于用戶(hù)方式對(duì)象,這意味著互斥對(duì)象的運(yùn)行速度比關(guān)鍵代碼段要慢,但也意味著不同進(jìn)程的多個(gè)線(xiàn)程能夠訪(fǎng)問(wèn)單個(gè)互斥對(duì)象,并且線(xiàn)程在等待訪(fǎng)問(wèn)資源時(shí)可以設(shè)定一個(gè)超時(shí)值。ID用于標(biāo)識(shí)系統(tǒng)中的那個(gè)線(xiàn)程當(dāng)前擁有互斥對(duì)象,遞歸計(jì)數(shù)器用于指明該線(xiàn)程擁有互斥對(duì)象的次數(shù)。互斥對(duì)象是常用內(nèi)核對(duì)象之一,通常是用于保護(hù)由多個(gè)線(xiàn)程訪(fǎng)問(wèn)的內(nèi)存塊,互斥對(duì)象保證訪(fǎng)問(wèn)內(nèi)存塊的任何線(xiàn)程擁有對(duì)該內(nèi)存塊的獨(dú)占訪(fǎng)問(wèn)權(quán),這樣可保證數(shù)據(jù)的完整性。互斥對(duì)象使用規(guī)則如下:

1)? 如果線(xiàn)程ID0(這是無(wú)效的ID值),互斥對(duì)象不被任何線(xiàn)程所擁有,并且發(fā)出該互斥對(duì)象的通知信號(hào);

2)? 如果ID是非0數(shù)字,那么一個(gè)線(xiàn)程就擁有互斥對(duì)象,并且不發(fā)出該互斥對(duì)象的通知信號(hào);

3)? 與所有其他內(nèi)核對(duì)象不同,互斥對(duì)象在操作系統(tǒng)中擁有特殊的代碼,允許它們違反正常的規(guī)則;

若要使用互斥對(duì)象,需要調(diào)用CreateMutex來(lái)創(chuàng)建互斥內(nèi)核對(duì)象:

HANDLE CreateMutex(

??????????????????????????? PSECURITY_ATTRIBUTES psa,

??????????????????????????? BOOL fInitialOwner,

??????????????????????????? PCTSTR pszName);

通過(guò)調(diào)用OpenMutex,另一個(gè)進(jìn)程可以獲得現(xiàn)有互斥對(duì)象相關(guān)的句柄:

HANDLE OpenMutex(

??????????????????????????? DWORD fdwAccess,

??????????????????????????? BOOL bInheritHandle,

??????????????????????????? PCTSTR pszName);

其中,參數(shù)fInitialOwner用于控制互斥對(duì)象的初始狀態(tài),如果傳遞FALSE(通常情況下傳遞的值),那互斥對(duì)象的ID和遞歸計(jì)數(shù)器被設(shè)置為0,這意味著該互斥對(duì)象沒(méi)有被任何線(xiàn)程所擁有,因此要發(fā)出它的通知信號(hào)。如果fInitialOwner參數(shù)傳遞TRUE,那么該對(duì)象的線(xiàn)程ID被設(shè)置為調(diào)用線(xiàn)程的ID,遞歸計(jì)數(shù)器被設(shè)置為1,由于ID是個(gè)非0數(shù)字,因此該互斥對(duì)象開(kāi)始時(shí)不發(fā)出通知信號(hào)。

對(duì)于互斥對(duì)象來(lái)說(shuō),正常的內(nèi)核對(duì)象的已通知和未通知規(guī)則存在一個(gè)特殊的異常情況,比如說(shuō):一個(gè)線(xiàn)程試圖等待一個(gè)未通知的互斥對(duì)象,在這種情況下,該線(xiàn)程通常被置于等待狀態(tài),然而系統(tǒng)要查看試圖獲取互斥對(duì)象的線(xiàn)程ID是否與互斥對(duì)象中記錄的線(xiàn)程ID相同,如果相同,即使互斥對(duì)象處于未通知狀態(tài),系統(tǒng)也允許線(xiàn)程保持可調(diào)度狀態(tài),這種“異常”行為特性不適用于系統(tǒng)中的其他內(nèi)核對(duì)象。每當(dāng)線(xiàn)程成功地等待互斥對(duì)象時(shí),該對(duì)象的遞歸計(jì)數(shù)器就遞增,若要使遞歸計(jì)數(shù)器的值大于1,唯一的方法是線(xiàn)程多次等待相同的互斥對(duì)象,以便利用這個(gè)異常規(guī)則。一旦線(xiàn)程成功等待到一個(gè)互斥對(duì)象,該線(xiàn)程就知道它已經(jīng)擁有對(duì)受保護(hù)資源的獨(dú)占訪(fǎng)問(wèn)權(quán),試圖訪(fǎng)問(wèn)該資源的任何其他線(xiàn)程(通過(guò)等待相同的互斥對(duì)象)均被置于等待狀態(tài)中。當(dāng)目前擁有對(duì)資源訪(fǎng)問(wèn)權(quán)的線(xiàn)程不再需要它的訪(fǎng)問(wèn)權(quán)時(shí),需要調(diào)用ReleaseMutex函數(shù)來(lái)釋放該互斥對(duì)象:

BOOL ReleaseMutex(HANDLE hMutex);

該函數(shù)將對(duì)象遞歸技數(shù)器遞減1,如果線(xiàn)程多次成功等待一個(gè)互斥對(duì)象,在互斥對(duì)象的遞歸計(jì)數(shù)器變成0之前,該線(xiàn)程必須以同樣次數(shù)調(diào)用ReleaseMutex函數(shù),當(dāng)遞歸計(jì)數(shù)器到達(dá)0時(shí),該線(xiàn)程ID也被置為0,同時(shí)該對(duì)象變?yōu)橐淹ㄖ獱顟B(tài)。當(dāng)一個(gè)線(xiàn)程調(diào)用ReleaseMutex函數(shù)時(shí),函數(shù)要查看調(diào)用線(xiàn)程的ID是否與互斥對(duì)象中的線(xiàn)程ID相匹配,如相同,遞歸計(jì)數(shù)器就遞減,如不匹配,那函數(shù)將不進(jìn)行任何操作,而是將FALSE(表示失敗)返回給調(diào)用者,此時(shí)調(diào)用GetLastError,將返回ERROR_NOT_OWNER(試圖釋放不是調(diào)用者擁有的互斥對(duì)象)。如在釋放互斥對(duì)象之前,擁有互斥對(duì)象的線(xiàn)程終止運(yùn)行(使用ExitThreadTerminateThreadExitProcessTerminateProcess函數(shù)),系統(tǒng)將該互斥對(duì)象視為已經(jīng)被放棄——擁有互斥的線(xiàn)程決不會(huì)釋放它,因?yàn)樵摼€(xiàn)程已經(jīng)終止運(yùn)行。

總結(jié)下線(xiàn)程同步對(duì)象(內(nèi)核對(duì)象)與線(xiàn)程同步之間的相互關(guān)系:

1)對(duì)象:進(jìn)程,何時(shí)處于未通知狀態(tài):當(dāng)進(jìn)程仍然活動(dòng)時(shí),何時(shí)處于已通知狀態(tài):當(dāng)進(jìn)程終止運(yùn)行時(shí)(ExitProcess,TerminateProcess),成功等待的副作用:無(wú);

2)對(duì)象:線(xiàn)程,何時(shí)處于未通知狀態(tài):當(dāng)線(xiàn)程仍然活動(dòng)時(shí),何時(shí)處于已通知狀態(tài):當(dāng)線(xiàn)程終止運(yùn)行時(shí)(ExitThread,TerminateThread),成功等待的副作用:無(wú);

3)對(duì)象:作業(yè),何時(shí)處于未通知狀態(tài):當(dāng)作業(yè)的時(shí)間尚未結(jié)束時(shí),何時(shí)處于已通知狀態(tài):當(dāng)作業(yè)的時(shí)間結(jié)束時(shí),成功等待的副作用:無(wú);

4)對(duì)象:文件,何時(shí)處于未通知狀態(tài):當(dāng)I/O請(qǐng)求正在處理時(shí),何時(shí)處于已通知狀態(tài):當(dāng)I/O請(qǐng)求處理完畢時(shí),成功等待的副作用:無(wú);

5)對(duì)象:控制臺(tái)輸入,何時(shí)處于未通知狀態(tài):不存在任何輸入,何時(shí)處于已通知狀態(tài):當(dāng)存在輸入時(shí),成功等待的副作用:無(wú);

6)對(duì)象:文件修改通知,何時(shí)處于未通知狀態(tài):沒(méi)有任何文件被修改,何時(shí)處于已通知狀態(tài):當(dāng)文件系統(tǒng)發(fā)現(xiàn)修改時(shí),成功等待的副作用:重置通知;

7)對(duì)象:自動(dòng)重置事件,何時(shí)處于未通知狀態(tài):ResetEvent,Pulse-Event或等待成功,何時(shí)處于已通知狀態(tài):當(dāng)調(diào)用SetEvent/PulseEvent時(shí),成功等待的副作用:重置事件;

8)對(duì)象:人工重置事件,何時(shí)處于未通知狀態(tài):ResetEvent,Pulse-Event,何時(shí)處于已通知狀態(tài):當(dāng)調(diào)用SetEvent/PulseEvent時(shí),成功等待的副作用:無(wú)

9)對(duì)象:自動(dòng)重置等待定時(shí)器,何時(shí)處于未通知狀態(tài):CancelWaitableTimer或等待成功,何時(shí)處于已通知狀態(tài):當(dāng)時(shí)間到時(shí)(SetWaitableTimer),成功等待的副作用:重置定時(shí)器;

10)對(duì)象:人工重置等待定時(shí)器,何時(shí)處于未通知狀態(tài):CancelWaitableTimer,何時(shí)處于已通知狀態(tài):當(dāng)時(shí)間到時(shí)(SetWaitableTimer),成功等待的副作用:無(wú);

11)對(duì)象:信標(biāo),何時(shí)處于未通知狀態(tài):等待成功,何時(shí)處于已通知狀態(tài):當(dāng)數(shù)量>0時(shí)(ReleaseSemaphore),成功等待的副作用:數(shù)量遞減1

12)對(duì)象:互斥對(duì)象,何時(shí)處于未通知狀態(tài):等待成功,何時(shí)處于已通知狀態(tài):當(dāng)未被線(xiàn)程擁有時(shí)(ReleaseMutex),成功等待的副作用:將所有權(quán)賦予線(xiàn)程;

13)對(duì)象:關(guān)鍵代碼段(用戶(hù)方式),何時(shí)處于未通知狀態(tài):等待成功((TryEnterCriticalSection),何時(shí)處于已通知狀態(tài):當(dāng)未被線(xiàn)程擁有時(shí)(LeaveCriticalSection),成功等待的副作用:將所有權(quán)賦予線(xiàn)程。

互鎖(用戶(hù)方式)函數(shù)決不會(huì)導(dǎo)致線(xiàn)程變?yōu)榉钦{(diào)度狀態(tài),它們會(huì)改變一個(gè)值并立即返回。

線(xiàn)程同步函數(shù)WaitForSingleObjectWaitForMultipleObjects是使用最多的函數(shù),不過(guò),Windows還提供了其他函數(shù)。異步設(shè)備I/O使得線(xiàn)程能夠啟動(dòng)一個(gè)讀操作或?qū)懖僮?#xff0c;但是不必等待讀操作或?qū)懖僮魍瓿伞@?#xff0c;如果線(xiàn)程需要將一個(gè)大文件裝入內(nèi)存,那該線(xiàn)程可以告訴系統(tǒng)將文件裝入內(nèi)存,在系統(tǒng)加載該文件時(shí),線(xiàn)程可以執(zhí)行其他任務(wù),如創(chuàng)建窗口、對(duì)內(nèi)部數(shù)據(jù)結(jié)構(gòu)進(jìn)行初始化等等,當(dāng)初始化操作完成時(shí),線(xiàn)程可以終止自己的運(yùn)行,等待系統(tǒng)通知文件已經(jīng)讀取。設(shè)備對(duì)象是可以同步的內(nèi)核對(duì)象,這意味著可以調(diào)用WaitForSingleObject函數(shù),傳遞文件、套接字和通信端口的句柄。當(dāng)系統(tǒng)執(zhí)行異步I/O時(shí),設(shè)備對(duì)象處于未通知狀態(tài),一旦操作完成,系統(tǒng)就將對(duì)象的狀態(tài)改為已通知狀態(tài),這樣,線(xiàn)程就知道操作已經(jīng)完成,此時(shí)線(xiàn)程可繼續(xù)運(yùn)行。線(xiàn)程可以調(diào)用WaitForInputIdle來(lái)終止自己的運(yùn)行:

DWORD WaitForInputIdle(

??????????????????????????? HANDLE hProcess,

??????????????????????????? DWORD dwMilliseconds);

該函數(shù)一直處于等待狀態(tài),知道hProcess標(biāo)識(shí)的進(jìn)程在創(chuàng)建應(yīng)用程序的第一個(gè)窗口的線(xiàn)程中已經(jīng)沒(méi)有尚未處理的輸入為止。

線(xiàn)程可以調(diào)用MsgWaitForMultipleObjectsMsgWaitForMultipleObjectsEx函數(shù),讓線(xiàn)程等待它自己的消息:

DWORD MsgWaitForMultipleObjects(

????????????????????????????????????????? DWORD dwCount,

????????????????????????????????????????? PHANDLE phObjects,

????????????????????????????????????????? BOOL fWaitAll,

????????????????????????????????????????? DWORD dwMilliseconds,

????????????????????????????????????????? DWORD dwWakeMask);

DWORD MsgWaitForMultipleObjects(

????????????????????????????????????????? DWORD dwCount,

????????????????????????????????????????? PHANDLE phObjects,

????????????????????????????????????????? BOOL fWaitAll,

????????????????????????????????????????? DWORD dwMilliseconds,

????????????????????????????????????????? DWORD dwWakeMask,

DWORD dwFlags);

這些函數(shù)與WaitForMultipleObjects函數(shù)十分相似,差別在于它們?cè)试S線(xiàn)程在內(nèi)核對(duì)象變成已通知狀態(tài)或窗口消息需要調(diào)度到調(diào)用線(xiàn)程創(chuàng)建的窗口中時(shí)被調(diào)度。

線(xiàn)程同步函數(shù)還有WaitForDebugEvent函數(shù):當(dāng)調(diào)試程序啟動(dòng)運(yùn)行時(shí),它將自己附加給一個(gè)被調(diào)試程序;SingleObjectAndWait函數(shù)用于在單個(gè)原子方式的操作中發(fā)出關(guān)于內(nèi)核對(duì)象的通知并等待另一個(gè)內(nèi)核對(duì)象。

?????????????????????????????????? 如非

????????????????????????????????????? 2009-1-15

《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專(zhuān)家共同創(chuàng)作,文字、視頻、音頻交互閱讀

總結(jié)

以上是生活随笔為你收集整理的线程与内核对象的同步——Windows核心编程学习手札之九的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。