Win32多線程編程-線程同步與通信_第1頁
Win32多線程編程-線程同步與通信_第2頁
Win32多線程編程-線程同步與通信_第3頁
Win32多線程編程-線程同步與通信_第4頁
Win32多線程編程-線程同步與通信_第5頁
已閱讀5頁,還剩5頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、線程間數(shù)據(jù)通信系統(tǒng)從進(jìn)程的地址空間中分配內(nèi)存給線程棧使用。新線程與創(chuàng)建它的線程在相同的進(jìn)程上下文中運(yùn)行。因此,新線程可以訪問進(jìn)程內(nèi)核對象的所有句柄、進(jìn)程中的所有內(nèi)存以及同一個進(jìn)程中其他所有線程的棧。這樣一來,同一個進(jìn)程中的多個線程可以很容易的相互通信。到目前為止,將數(shù)據(jù)從一個線程傳到另一個線程的惟一方法是在創(chuàng)建線程時傳遞給新線程一個指針參數(shù)(LPVOIDlpParam)。參數(shù)lpParam為LPVOID指針類型,我們可在其中存儲普通的數(shù)值(size為平臺地址總線寬度),也可以存放指向某個數(shù)據(jù)結(jié)構(gòu)(struct或class)的地址。在新線程函數(shù)中,解引用時需要強(qiáng)制類型轉(zhuǎn)換回原類型,以進(jìn)行正確的訪

2、問。以下代碼段演示了一個典型的多線程場景。/AtypicalmultithreadsceneDWORDWINAPIFirstThread(PVOIDlpParam)/Initializeastack-basedvariableintx=0;DWORDdwThreadID;/Createanewthread.HANDLEhThread=CreateThread(NULL,0,SecondThread,(LPVOID)&x,0,&dwThreadID);/Wedontreferencethenewthreadanymore,/socloseourhandletoit.CloseHandle(hTh

3、read);/Ourthreadisdone./BUG:ourstackwillbedestroyed,/butSecondThreadmighttrytoaccessit.return0;DWORDWINAPISecondThread(LPVOIDlpParam)/Dosomelengthyprocessinghere././AttempttoaccessthevariableonFirstThreadsstack./NOTE:Thismaycauseanaccessviolation-itdependsontiming!*(int*)lpParam)=5;/.return0;上述場景中,W

4、indows沒有維持線程之間的“父子關(guān)系“,即父線程FirstThread已經(jīng)終止運(yùn)行,而子線程SecondThread仍在繼續(xù)運(yùn)行。以上父子關(guān)系只是為了一種解說上的方便,實(shí)際上FirstThread和SecondThread具有相同的優(yōu)先級(默認(rèn)是normal),因此它們“同時”執(zhí)行。這樣,F(xiàn)irstThread在開辟SecondThread后,不等SecondThread運(yùn)行至代碼*(int*)lpParam)=5;即可能退出。FirstThread棧上的自動變量x已銷毀,而SecondThread試圖去訪問之,將導(dǎo)致AccessViolation。這是多線程編程中新手常犯的錯誤。解決以上

5、問題,大概有以下三種方案。讓創(chuàng)建線程等待新線程退出后才退出。在FirstThread中代碼CloseHandle(hThread);之前WaitForSingleObject(hThread,INFINITE);這樣保證SecondThread中對FirstThread棧中自動變量x的訪問有效期。將x聲明為堆變量,即int*px=newint;,在SecondThread中對px進(jìn)行訪問完畢后調(diào)用deletepx;釋放堆內(nèi)存。由于堆內(nèi)存對進(jìn)程有效,因此,上述代碼中FirstThread先退出,在SecondThread中對px的訪問依然有效,直到進(jìn)程的某處將該內(nèi)存delete掉。這是在需要動態(tài)

6、創(chuàng)建線程參數(shù)(數(shù)據(jù)結(jié)構(gòu))時的一種解決方案,實(shí)際應(yīng)用中經(jīng)常用到。將x聲明為靜態(tài)變量staticintx=0;則將存儲在靜態(tài)存儲區(qū)域。這里有全局和局部之分,若在FirstThread之前聲明,則整個程序均可顯式訪問x;若在FirstThread之中聲明,貝Ix只在FirstThread中可見。當(dāng)然這里傳址給SecondThread,SecondThread可按址訪問。在方案(3)中,若在FirstThread之中將x聲明為靜態(tài)變量,將使函數(shù)SecondThread不可重入。換言之,不能創(chuàng)建兩個使用相同線程函數(shù)的線程,因?yàn)檫@兩個線程將共享同一個靜態(tài)變量。這涉及到下文將要闡述的線程同步問題。二多線程同

7、步互斥問題1同步問題的導(dǎo)入多個線程共享數(shù)據(jù)時,同時讀沒有問題,但如果同時讀和寫,情況就不同了。在本次線程內(nèi),讀取一個變量時,為提高存取速度,編譯器優(yōu)化時,有時會先把變量讀取到一個寄存器中;以后取變量值時,就直接從寄存器中取值;當(dāng)變量值在本線程中改變時,會同時把變量的新值拷貝到該寄存器中,以便保持一致;當(dāng)變量在因別的線程等而改變了值,該寄存器的值不會相應(yīng)改變,從而造成應(yīng)用程序讀取的值和實(shí)際的變量值不一致。/CountError#include#include#includeintg_nCount1=0;intg_nCount2=0;BOOLg_bContinue=TRUE;UINT_stdcal

8、lThreadFunc(LPVOID);intmain(intargc,char*argv)UINTuId;HANDLEh2;h0=(HANDLE):_beginthreadex(NULL,0,ThreadFunc,NULL,0,&uId);h1=(HANDLE):_beginthreadex(NULL,0,ThreadFunc,NULL,0,&uId);/等待1秒后通知兩個計(jì)數(shù)線程結(jié)束,關(guān)閉句柄Sleep(1000);g_bContinue=FALSE;/等待兩個線程都運(yùn)行完:WaitForMultipleObjects(2,h,TRUE,INFINITE);:CloseHandle(h0)

9、;:CloseHandle(h1);printf(g_nCount1=%dn,g_nCount1);printf(g_nCount2=%dn,g_nCount2);return0;UINT_stdcallThreadFunc(LPVOID)while(g_bContinue)g_nCount1+;g_nCount2+;return0;以上代碼中線程h0和h1(具有相同的線程函數(shù)ThreadFunc)同時增加全局變量g_nCount1和g_nCount2的計(jì)數(shù)。按道理來說最終在主線程中輸出的它們的值應(yīng)該是相同的,可是結(jié)果卻并不盡如人意。上述測試中,g_nCount1和g_nCount2的值往往并

10、不相同。出現(xiàn)此種結(jié)果主要是因?yàn)橥瑫r訪問g_nCount1和g_nCount2的兩個線程具有相同的優(yōu)先級。在執(zhí)行過程中,如果第一個線程取走g_nCount1的值準(zhǔn)備進(jìn)行自加操作的時候,它的時間片恰好用完,系統(tǒng)切換到第二個線程去對g_nCount1進(jìn)行自加操作;一個時間片過后,第一個線程再次被調(diào)度,此時它會將上次取出的值自加,并放入g_nCount1所在的內(nèi)存里,這就會覆蓋掉第二個線程對g_nCount1的自加操作。變量g_nCount2也存在相同的問題。由于這樣的事情的發(fā)生次數(shù)是不可預(yù)知的,所以最終它們的值就不相同了。針對以上問題,可使用volatile修飾靜態(tài)變量去優(yōu)化,直接存取原始內(nèi)存地址。

11、對于volatile變量,優(yōu)化器在用到這個變量時每次都必須小心地重新讀取這個變量的值,而不是使用保存在寄存器里的備份。這對于經(jīng)常同硬件、中斷、等等打交道的嵌入式系統(tǒng)程序而言,是一種很好的解決方案。但常規(guī)情況下,很少使用去優(yōu)化的方式。上例中,g_nCount1和g_nCount2是全局變量,屬于該進(jìn)程內(nèi)所有線程共有的資源。解決問題的關(guān)鍵在于在一個線程對某個對象進(jìn)行操作的過程中,需要有某種機(jī)制阻止其他線程的操作,這將涉及到到同步、互斥等話題。2同步與互斥的概念同步與互斥往往像一對孿生兄弟,總是在同一語境中被提及,但往往語焉不詳。下面厘清一下它們之間的曖昧。互斥:是指某一資源同時只允許一個訪問者對其

12、進(jìn)行訪問,具有唯一性和排它性。但互斥無法限制訪問者對資源的訪問順序,即訪問是無序的。同步:是指在互斥的基礎(chǔ)上(大多數(shù)情況),通過其它機(jī)制實(shí)現(xiàn)訪問者對資源的有序訪問。在大多數(shù)情況下,同步已經(jīng)實(shí)現(xiàn)了互斥,特別是所有寫入資源的情況必定是互斥的。少數(shù)情況是指可以允許多個訪問者同時訪問資源。大街上的移動廁所往往只有一個茅坑,如果把廁所(茅坑)當(dāng)做一種資源,則某一時刻,這種珍貴的資源只允許一人享用。這種對資源使用的獨(dú)占性和排他性即互斥。上述上廁所場景中,互斥這一原則的約束下,內(nèi)急者先來先上,維持了良好的公共秩序。從同步的制約性要素考慮,上廁所行為不存在“同步”問題。因?yàn)锳上完廁所即可走人,接下來輪到B,B

13、進(jìn)行與A幾乎完全一樣的獨(dú)立操作,A和B也許素昧平生,它們之間不存在任何的制約關(guān)系。關(guān)于同步的典型案例是“生產(chǎn)者-消費(fèi)者”模型。生產(chǎn)者占用緩沖區(qū)時,消費(fèi)者不能占用,反之亦然,這個即互斥;消費(fèi)者必須要等生產(chǎn)者生產(chǎn)之后,才能消費(fèi),這個即同步。在這里,同步與互斥形影相隨,同步中暗含互斥。同時,可以看出,生產(chǎn)者和消費(fèi)者的同步關(guān)系本質(zhì)上是一種供需制約關(guān)系。3多線程同步策略多線程同步就要保證在一個線程占有公共資源的時候,其他線程不會再次占有這個資源所以,解決同步問題,就是保證整個存取過程的獨(dú)占性。同步可以保證在一個時間內(nèi)只有一個線程對某個共享資源有控制權(quán),其本質(zhì)是微觀串行所體現(xiàn)出來的等待。之前談到的那個計(jì)數(shù)

14、錯誤(CountError)問題,涉及到如何協(xié)調(diào)線程間的活動,以保證對資源的正確訪問。Windows操作系統(tǒng)提供了多種同步手段,同步對象包括臨界區(qū)(CriticalSection)、事件(Event)、信號量(Semaphore)、互斥量(Mutex)等。(1)臨界區(qū)對象(CRITICAL_SECTION),也稱關(guān)鍵代碼段臨界區(qū)對象依賴一個CRITICAL_SECTION數(shù)據(jù)結(jié)構(gòu)記錄一些信息,確保在同一時間只有一個線程訪問該數(shù)據(jù)段中的數(shù)據(jù)。使用臨界區(qū)實(shí)施同步,首先需要聲明一個CRITICAL_SECTION結(jié)構(gòu)。對CRITICAL_SECTION結(jié)構(gòu)的操作包括Initialize、Enter/

15、Leave、Delete。編程的時候,要把臨界區(qū)對象定義在想保護(hù)的數(shù)據(jù)段中,然后在任何線程使用此臨界區(qū)對象之前,調(diào)用InitializeCriticalSection函數(shù)對它進(jìn)行初始化。/TheInitializeCriticalSectionfunctioninitializesacriticalsectionobject.VOIDInitializeCriticalSection(LPCRITICAL_SECTIONlpCriticalSection/criticalsection);之后,線程訪問臨界區(qū)中數(shù)據(jù)的時候,必須首先調(diào)用EnterCriticalSection函數(shù),申請進(jìn)入臨界區(qū)

16、。在同一時間內(nèi),Windows只允許一個線程進(jìn)入臨界區(qū)。所以在申請的時候,如果有另一個線程在臨界區(qū)的話,EnterCriticalSection函數(shù)會一直等待下去,直到其他線程離開臨界區(qū)才返回。/TheEnterCriticalSectionfunctionwaitsforownershipofthespecifiedcriticalsectionobject.Thefunctionreturnswhenthecallingthreadisgrantedownership.VOIDEnterCriticalSection(LPCRITICAL_SECTIONlpCriticalSection/

17、criticalsection);當(dāng)操作完成的時候,要調(diào)用LeaveCriticalSection函數(shù)將臨界區(qū)交還給Windows系統(tǒng),以便其他線程可以申請使用。否則,就是占著茅坑不拉屎憋死其他人的不道德行為。/TheLeaveCriticalSectionfunctionreleasesownershipofthespecifiedcriticalsectionobject.VOIDLeaveCriticalSection(LPCRITICAL_SECTIONlpCriticalSection/criticalsection);當(dāng)程序不再使用臨界區(qū)對象的時候,必須使用DeleteCritic

18、alSection函數(shù)執(zhí)行刪除操作,釋放資源。/TheDeleteCriticalSectionfunctionreleasesallresourcesusedbyanunownedcriticalsectionobject.VOIDDeleteCriticalSection(LPCRITICAL_SECTIONlpCriticalSection/criticalsection);聲明一個CRITICAL_SECTION對象,即政府修建了一座廁所。廁所這一資源起初是上鎖的,Initialize可看做廁所開鎖對外開放,使廁所可用。Enter可看做上廁所的排隊(duì)過程,一旦茅坑空出,即可持票進(jìn)入享用;

19、Leave可看做如廁完畢沖水走人。廁所被很多人Enter/Leave用了幾年后,其使命結(jié)束,政府依據(jù)城市規(guī)劃,將其拆掉一Delete收回。臨界區(qū)對象能夠很好地保護(hù)共享數(shù)據(jù),但是它不能夠用于進(jìn)程之間資源的鎖定。由于它不是內(nèi)核對象,故臨界區(qū)只能用于在同一進(jìn)程內(nèi)的線程同步。如果要在進(jìn)程間維持線程的同步,可以使用事件內(nèi)核對象。(2)事件內(nèi)核對象(event)多線程程序設(shè)計(jì)大多會涉及線程間相互通信。主線程在創(chuàng)建工作線程的時候,可以通過參數(shù)給工作線程傳遞初始化數(shù)據(jù),當(dāng)工作線程開始運(yùn)行后,還需要通過通信機(jī)制來控制工作線程。同樣,工作線程有時候也需要將一些情況主動通知主線程。事件內(nèi)核對象是一種比較好的通信方法

20、。事件對象(event)是一種抽象的對象,它也有未受信(nonsignaled)和受信(signaled)兩種狀態(tài)。編程人員也可以使用WaitForSingleObject/WaitForMultipleObjects函數(shù)等待其變成受信狀態(tài)。不同于其他內(nèi)核對象,系統(tǒng)提供的一些API可以使事件對象在這兩種狀態(tài)之間轉(zhuǎn)化??梢园咽录ο罂闯墒且粋€設(shè)置在Windows內(nèi)部的標(biāo)志,它的狀態(tài)設(shè)置和測試工作由Windows來完成。事件對象包含3個成員:nUsageCount(使用計(jì)數(shù))、bManualReset(是否人工重置)和bSignaled(是否受信)。成員nUsageCount記錄了當(dāng)前的使用計(jì)數(shù),

21、當(dāng)使用計(jì)數(shù)為0的時候,Windows就會銷毀此內(nèi)核對象占用的資源;成員bManualReset指定在一個事件內(nèi)核對象上等待的函數(shù)返回之后,Windows是否重置這個對象為未受信狀態(tài);成員bSignaled指定當(dāng)前事件內(nèi)核對象是否受信。下面要介紹的操作事件內(nèi)核對象的函數(shù)會影響這些成員的值。要使用事件對象,首先用CreateEvent函數(shù)去創(chuàng)建它。/TheCreateEventfunctioncreatesoropensanamedorunnamedeventobject.HANDLECreateEvent(LPSECURITY_ATTRIBUTESlpEventAttributes,/SDBOO

22、LbManualReset,/resettypeBOOLbInitialState,/initialstateLPCTSTRlpName/objectname);參數(shù)一為事件對象的安全屬性,一般填充NULL表示取默認(rèn)值。參數(shù)二,選擇事件對象的重置方式以決定類型。bManualReset=TRUE則表示人工重置(manual-reset);bManualReset=FALSE貝I表示自動重置(auto-reset)。當(dāng)一個人工重置的事件對象受信以后,所有等待在這個事件上的線程都會變?yōu)榭烧{(diào)度狀態(tài);當(dāng)一個自動重置的事件對象受信以后,Windows僅允許一個等待在該事件上的線程變成可調(diào)度狀態(tài),然后就自

23、動重置此事件對象為未受信狀態(tài)。通常使用自動重置的事件內(nèi)核對象,即設(shè)置bManualReset=FALSE。參數(shù)三bInitialState對應(yīng)著bSignaled成員的初態(tài)。若將它設(shè)為TRUE,則表示事件對象創(chuàng)建時的初始狀態(tài)為受信;若將它設(shè)為FALSE,則初始狀態(tài)為未受信。通常設(shè)置初始狀態(tài)為未受信,即置bInitialState=FALSE。參數(shù)四指定事件對象的名稱,以便跨進(jìn)程按名訪問??邕M(jìn)程訪問事件內(nèi)核對象,可傳入事件對象名調(diào)用OpenEvent獲取該對象的句柄。/TheOpenEventfunctionopensanexistingnamedeventobject.HANDLEOpenEv

24、ent(DWORDdwDesiredAccess,/accessBOOLbInheritHandle,/inheritanceoptionLPCTSTRlpName/objectname);系統(tǒng)創(chuàng)建或打開一個事件內(nèi)核對象后,會返回事件的句柄。當(dāng)編程人員不使用此內(nèi)核對象的時候,應(yīng)該調(diào)用CloseHandle函數(shù)釋放它占用的資源。事件對象被建立后,程序可以通過SetEvent和ResetEvent函數(shù)來設(shè)置它的狀態(tài)。/TheSetEventfunctionsetsthespecifiedeventobjecttothesignaledstate.BOOLSetEvent();HANDLEhEven

25、t/handletoevent/TheResetEventfunctionsetsthespecifiedeventobjecttothenonsignaledstate.BOOLResetEvent(HANDLEhEvent/handletoevent);與SetEvent/ResetEvent相關(guān)的另一個函數(shù)是PulseEvent。顧名思義,所謂PulseEvent即瞬間Set/Reset,至于這個瞬間多長及其效用,這里不詳解??蓞⒖缄P(guān)于線程同步PulseEvent()/ThePulseEventfunctionsetsthespecifiedeventobjecttothesignale

26、dstateandthenresetsittothenonsignaledstateafterreleasingtheappropriatenumberofwaitingthreads.BOOLPulseEvent(HANDLEhEvent/handletoeventobject);事件內(nèi)核對象的同步,代碼上體現(xiàn)在對WaitForSingleObject/WaitForMultipleObjects函數(shù)的調(diào)用,等待事件對象的置信。我們可以將之想象為廁所門外的“有人/沒人”信號燈,紅燈有人(nonsignaled),綠燈無人(signaled)。事件對象是一個用于線程間通信被廣泛使用的內(nèi)核對象。

27、因?yàn)樗且粋€內(nèi)核對象,所以也可以跨進(jìn)程使用。依靠在線程間通信就可以使各線程的工作協(xié)調(diào)進(jìn)行,達(dá)到同步的目的。(3)信號量內(nèi)核對象(Semaphore)信號量內(nèi)核對象對線程的同步方式與前面幾種不同,它允許多個線程在同一時刻訪問某一資源,但是需要限制同一時刻訪問此資源的最大線程數(shù)目。首先使用CreateSemaphore函數(shù)創(chuàng)建信號量內(nèi)核對象。/TheCreateSemaphorefunctioncreatesoropensanamedorunnamedsemaphoreobject.HANDLECreateSemaphore(LPSECURITY_ATTRIBUTESlpSemaphoreAttr

28、ibutes,/SDLONGlInitialCount,/initialcountLONGlMaximumCount,/maximumcountLPCTSTRlpName/objectname);CreateSemaphore函數(shù)創(chuàng)建信號量時,參數(shù)三指定允許的最大資源計(jì)數(shù),參數(shù)二指定當(dāng)前可用的初始資源計(jì)數(shù)。一般將lInitialCount設(shè)置與lMaximumCount相等。參數(shù)四即內(nèi)核對象名稱,以便跨進(jìn)程執(zhí)行OpenSemaphore按名訪問。只要當(dāng)前可用資源計(jì)數(shù)大于0,就可以發(fā)出信號量信號,在該信號量上的等待函數(shù)調(diào)用WaitForSingleObject返回。每增加一個線程對共享資源的訪問

29、,當(dāng)前可用資源計(jì)數(shù)就會減1。WaitForSingleObject返回后,調(diào)用線程在對共享資源的同步處理完畢后,應(yīng)調(diào)用ReleaseSemaphore來增加當(dāng)前可用資源計(jì)數(shù)。否則,將會出現(xiàn)當(dāng)前正在處理共享資源的實(shí)際線程并沒有達(dá)到要限制的數(shù)值,而其他線程卻因?yàn)楫?dāng)前可用資源計(jì)數(shù)為0而仍無法進(jìn)入的情況。/TheReleaseSemaphorefunctionincreasesthecountofthespecifiedsemaphoreobjectbyaspecifiedamount.BOOLReleaseSemaphore(HANDLEhSemaphore,LONGlReleaseCount,/h

30、andletosemaphore/countincrementamountLPLONGlpPreviousCount/previouscount);參數(shù)一為信號量內(nèi)核對象句柄;參數(shù)二為計(jì)數(shù)遞增值,一般設(shè)為1,當(dāng)然也可以按需要設(shè)置大于1的值;參數(shù)三為之前的計(jì)數(shù),往往填NULL,當(dāng)然可指定導(dǎo)出到當(dāng)?shù)刈兞?。信號量?nèi)核對象的同步,代碼上體現(xiàn)在對WaitForSingleObject/WaitForMultipleObjects函數(shù)的調(diào)用,其同步條件為資源計(jì)數(shù)大于0,即有可用資源。某個線程處理完共享資源后,需要調(diào)用ReleaseSemaphore釋放資源,增加可用資源計(jì)數(shù)。當(dāng)然,同其他內(nèi)核對象一樣,最終

31、也得調(diào)用CloseHandle函數(shù)釋放信號量內(nèi)核對象占用的資源。不同于過于簡陋的只有一個茅坑的移動廁所,豪華一點(diǎn)的公共廁所往往不止一個坑位。將坑位看做資源,則坑位的個數(shù)即信號量機(jī)制中的資源計(jì)數(shù)。這一排坑位,在同一時間內(nèi)也只能滿足部分人的需求,一個人一個坑,有人用完了釋放坑位,排隊(duì)的人才有機(jī)會進(jìn)入。信號量的使用特點(diǎn)使其更適用于對Socket程序中線程的同步問題。一個典型的場景就是HTTP服務(wù)器要對同一時間內(nèi)訪問同一頁面的用戶數(shù)加以限制,這是可以為每一個用戶對服務(wù)器的頁面請求設(shè)置一個線程,而頁面則是待保護(hù)的資源,通過使用信號量對線程的同步作用可以確保在任一時刻無論有多少用戶對某一頁面進(jìn)行訪問,只有

32、不大于設(shè)置的最大用戶數(shù)目的線程能夠進(jìn)行訪問,而其他訪問企圖被掛起。只有在有用戶退出對此頁面的訪問后,其他用戶的訪問請求才有可能得到響應(yīng)。迅雷的“原始地址線程數(shù)”即是設(shè)置客戶端從某一原始地址下載資源的最大線程數(shù)。當(dāng)然,資源所在的站點(diǎn)本身就會對某一客戶連接數(shù)有限制,這里的“某一客戶連接數(shù)”意即把文件拆開,一個線程下載一塊的多線程協(xié)助下載。當(dāng)然,多線程并不是越多越好,迅雷下載肯定使用的是線程池。迅雷將下載線程數(shù)限制為5,符合線程池的經(jīng)驗(yàn)公式,即線程池規(guī)模=CPU數(shù)*2+1現(xiàn)在機(jī)器基本都是雙核或多CPU的。當(dāng)用戶建立5個以上的下載任務(wù)時,迅雷最多同時執(zhí)行5個下載任務(wù),超出的任務(wù)將排隊(duì)等待。一旦有下載任

33、務(wù)完成,另一個等待下載任務(wù)即啟動。迅雷對于下載線程數(shù)的限制,即使用了信號量機(jī)制。(4)互斥內(nèi)核對象(Mutex)互斥是一種用途非常廣泛的內(nèi)核對象。能夠保證多個線程對同一共享資源的互斥訪問。同臨界區(qū)有些類似,只有擁有互斥對象的線程才具有訪問資源的權(quán)限。由于互斥對象只有一個,因此就決定了任何情況下,此共享資源都不會被多個線程所訪問。當(dāng)前占據(jù)資源的線程在任務(wù)處理完后應(yīng)該將占據(jù)的互斥對象交出,以便其他線程在其上的等待調(diào)用WaitForSingleObject/WaitForMultipleObjects返回?;诨コ鈨?nèi)核對象來保持線程同步用到的函數(shù)主要有CreateMutex、OpenMutex、Re

34、leaseMutex,其用法在代碼布局上同信號量內(nèi)核對象。/TheCreateMutexfunctioncreatesoropensanamedorunnamedmutexobject.HANDLECreateMutex(LPSECURITY_ATTRIBUTESlpMutexAttributes,/SDBOOLbInitialOwner,/initialownerLPCTSTRlpName/objectname);參數(shù)blnitialOwner主要用來控制互斥對象的初始狀態(tài),一般將其設(shè)為FALSE,以表明互斥對象在創(chuàng)建時并沒有為任何線程所占有。最后一個參數(shù)即內(nèi)核對象名稱,以便跨進(jìn)程執(zhí)行Ope

35、nMutex按名訪問。當(dāng)目前對資源具有訪問權(quán)限的線程不再需要訪問此資源而要離開時,必須通過ReleaseMutex函數(shù)來釋放其擁有的互斥對象。/TheReleaseMutexfunctionreleasesownershipofthespecifiedmutexobject.BOOLReleaseMutex(HANDLEhMutex/handletomutex);基于互斥內(nèi)核對象的同步在代碼上體現(xiàn)在對WaitForSingleObject/WaitForMultipleObjects函數(shù)的調(diào)用,以等待互斥內(nèi)核對象的通知,其同步條件為某一時刻只有一個線程擁有互斥對象。在互斥對象通知引起調(diào)用等待函

36、數(shù)返回時,等待函數(shù)的返回值不在是WAIT_OBJECT_0或WAIT_OBJECT_0,WAIT_OBJECT_0+nCount-1之間的某值,而是將返回WAIT_ABANDONED_0或是WAIT_ABANDONED_0,WAIT_ABANDONED_0+nCount-1之間的某值,以此來表明線程正在等待的互斥對象由另外一個線程所擁有,而此線程卻在使用完共享資源前就已經(jīng)終止除此之外,使用互斥內(nèi)核對象的方法在等待線程的可調(diào)度性上同使用其他幾種內(nèi)核對象的方法也有所不同,其他內(nèi)核對象在沒有得到通知時,受調(diào)用等待函數(shù)的作用,線程將會掛起,同時喪失可調(diào)度性,而使用互斥的方法可以在等待的同時仍具有調(diào)度性

37、,這也正是互斥對象所能完成的非常規(guī)操作之一。在編寫程序時,互斥對象多用在對那些為多個線程所訪問的內(nèi)存塊的保護(hù)上,可以確保任何線程在處理此內(nèi)存快時,都對其擁有可靠的獨(dú)占訪問權(quán)。(5)其他(互鎖函數(shù)和旋轉(zhuǎn)鎖)互鎖函數(shù)互鎖函數(shù)為同步訪問多線程共享變量提供了一個簡單的機(jī)制。如果變量在共享內(nèi)存,不同進(jìn)程的線程也可以使用此機(jī)制。用于互鎖的函數(shù)有InterlockedIncrement、InterlockedDecrement等。InterlockedIncrement函數(shù)遞增(加1)指定的32位變量。這個函數(shù)可以阻止其他線程同時使用此變量,函數(shù)原型如下。/TheInterlockedIncrementfu

38、nctionincrements(increasesbyone)thevalueofthespecifiedvariableandcheckstheresultingvalue.Thefunctionpreventsmorethanonethreadfromusingthesamevariablesimultaneously.LONGInterlockedIncrement(LPLONGvolatilelpAddend/variabletoincrement);InterlockedDecrement函數(shù)同步遞減(減1)指定的32位變量,原型如下。/TheInterlockedDecrementfunctiondecrements(decreasesbyone)thevalueofthespecifiedvariableandcheckstheresultingvalue.Thefunctionpreventsmorethanonethreadfromusingthesamevariablesimultaneously.LONGInt

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論