多線程編程技術(shù)詳解-第二講_第1頁
多線程編程技術(shù)詳解-第二講_第2頁
多線程編程技術(shù)詳解-第二講_第3頁
多線程編程技術(shù)詳解-第二講_第4頁
多線程編程技術(shù)詳解-第二講_第5頁
已閱讀5頁,還剩63頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

1、多線程編程技術(shù)詳解第二講:多線程的同步技術(shù)主講人:步磊峰步磊峰 UIPower 第一節(jié):線程同步1、當(dāng)所有線程能夠運(yùn)行而不需要相互通信的時(shí)候,操作系統(tǒng)進(jìn)入最佳運(yùn)行狀態(tài),但很少有線程能夠獨(dú)立運(yùn)行。2、線程間的通訊在很多情況下我們使用全局變量或者一些get函數(shù)獲得某些共享資源,在這種情況下這些全局變量或者共享資源都是跨線程的,因此不具有線程安全性。而局部變量是具有線程安全性的。第一節(jié):線程同步 1、需要多個(gè)線程訪問一個(gè)共享的資源,同時(shí)不能破壞資源的完整性 2、一個(gè)線程需要通知其他線程某項(xiàng)任務(wù)已經(jīng)完成了 至少在上面這兩種情況下,就需要引入線程的同步技術(shù)。第一節(jié):線程同步什么是線程同步線程同步可以理解

2、為線程A和B一塊配合,A執(zhí)行到一定程度時(shí)要依靠B的某個(gè)結(jié)果,于是停下來,示意B運(yùn)行;B依言執(zhí)行,再將結(jié)果給A;A再繼續(xù)操作。為什么要使用線程同步 在多線程環(huán)境中,線程之間經(jīng)常要同時(shí)訪問一些資源。那么勢必造成訪問共享資源沖突,怎么辦呢,為了解決這種沖突,Win32 API提供了多種同步控制對象來幫助程序員解決共享資源訪問沖突。第一節(jié):線程同步同步對象分類: 用戶模式下的同步對象: 例如關(guān)鍵段等 優(yōu)點(diǎn): 速度快 缺點(diǎn): 不能跨進(jìn)程,容易引起死鎖 內(nèi)核模式下的同步對象: 例如互斥量,信號量,事件等 優(yōu)點(diǎn): 跨進(jìn)程,安全性高 缺點(diǎn): 速度比用戶模式下的同步對象要慢很多第一節(jié):線程同步等待函數(shù)DWORD

3、 WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds);hHandle 對象句柄??梢灾付ㄒ幌盗械膶ο?,如Event(事件)、Mutex(互斥)、Semaphore(信號)、Thread(線程)等dwMilliseconds 定時(shí)時(shí)間間隔,單位為milliseconds(毫秒).如果指定一個(gè)非零值,函數(shù)處于等待狀態(tài)直到hHandle標(biāo)記的對象被觸發(fā),或者時(shí)間到了。如果dwMilliseconds為0,對象沒有被觸發(fā)信號,函數(shù)不會進(jìn)入一個(gè)等待狀態(tài),它總是立即返回。如果dwMilliseconds為INFINITE,對象被觸發(fā)信號后,函數(shù)

4、才會返回第一節(jié):線程同步等待函數(shù)DWORD WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds); DWORD dw = WaitForSingleObject(hProcess,5000) case WAIT_OBJECT_0; /the process terminated; break; case WAIT_TIMEOUT: /the process did not terminate within 5000 milliseconds; break; case WAIT_FAILED: /bad call to function

5、(invalid handle?) break; 第二節(jié):Mutex互斥對象1、用于確保一個(gè)線程獨(dú)占對一個(gè)資源的訪問。2、包含一個(gè)使用計(jì)數(shù)器,線程ID,以及一個(gè)遞歸計(jì)數(shù)器。3、線程的id用來標(biāo)識當(dāng)前占用這個(gè)互斥量的是系統(tǒng)中的哪個(gè)線程。4、遞歸計(jì)數(shù)器標(biāo)示這個(gè)線程占用該互斥量的次數(shù)。5、互斥量是使用最為頻繁的內(nèi)核對象之一第二節(jié):Mutex互斥對象規(guī)則:1、如果線程ID = 0,那么該互斥量不被任何線程占用,處于觸發(fā)狀態(tài)2、如果線程ID!=0 , 那么有一個(gè)線程占用了該互斥量,處于未觸發(fā)狀態(tài)第二節(jié):Mutex互斥對象CreateMutex函數(shù)CreateMutex函數(shù)功能是建立互斥體對象HANDLE

6、 CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, / 指向安全屬性的指針BOOL bInitialOwner, / 初始化互斥對象的所有者LPCTSTR lpName / 指向互斥對象名的指針);lpMutexAttributes 指定一個(gè)SECURITY_ATTRIBUTES結(jié)構(gòu),或傳遞零值bInitialOwner ,通常為FALSE,那么線程ID和遞歸計(jì)數(shù)器都被設(shè)置為0 lpName String,指定互斥體對象的名字。如已經(jīng)存在擁有這個(gè)名字的一個(gè)事件,則打開現(xiàn)有的已命名互斥體。這個(gè)名字可能不與現(xiàn)有的事件、信號機(jī)、可等待計(jì)時(shí)器或文

7、件映射相符第二節(jié):Mutex互斥對象ReleaseMutex函數(shù)釋放互斥對象BOOL WIANPI ReleaseMutex(HANDLE hMutex);hMutex:互斥對象的句柄 這個(gè)函數(shù)會將對象的遞歸計(jì)數(shù)器減1.如果線程成功的等待了互斥量對象不止一次,那么線程必須調(diào)用release相同的次數(shù)才能使對象的遞歸計(jì)數(shù)器變?yōu)?。當(dāng)遞歸計(jì)數(shù)器為0時(shí),函數(shù)還將線程ID設(shè)置為0,使互斥量處于觸發(fā)狀態(tài)。第二節(jié):Mutex互斥對象流程:1、假設(shè)有一個(gè)全局的文件指針,同時(shí)又有多個(gè)線程需要對該文件指針進(jìn)行讀寫。但是為了保證資源的完整性,我們在同一時(shí)刻,只允許一個(gè)線程進(jìn)行讀寫操作。為了獲得對被保護(hù)的資源的訪問

8、權(quán),線程要調(diào)用一個(gè)等待函數(shù)并轉(zhuǎn)入前面創(chuàng)建的互斥量句柄,在內(nèi)部,等待函數(shù)會檢查線程ID是否為0(也就是觸發(fā)狀態(tài)),如果為0,那么函數(shù)會把互斥量句柄中的線程id設(shè)為當(dāng)前調(diào)用線程的id,并把遞歸計(jì)數(shù)器設(shè)為1.此時(shí)互斥量就處于非觸發(fā)狀態(tài)。對互斥量的線程id賦值和遞歸計(jì)數(shù)器增加都是原子操作的。所謂原子操作就是指操作系統(tǒng)保證在完成原子操作之前,不進(jìn)行線程的切換。然后當(dāng)前線程繼續(xù)運(yùn)行。第二節(jié):Mutex互斥對象2、假設(shè)某一個(gè)線程獲成功的得到了互斥量,線程就知道自己獨(dú)占了對受保護(hù)的資源的訪問。那么任何試圖通過等待互斥量來獲得對資源的訪問權(quán)的線程將進(jìn)入等待狀態(tài)。很重要的一點(diǎn)是當(dāng)線程進(jìn)入等待狀態(tài)后,是不耗費(fèi)cpu

9、時(shí)鐘頻率的。當(dāng)獨(dú)占線程對資源操作完成后,必須要調(diào)用releaseMutex函數(shù)來將互斥量的遞歸計(jì)數(shù)器減1,如果遞歸計(jì)數(shù)器的值為0的話,那么還會將線程id設(shè)置為0.這樣互斥量又處于觸發(fā)狀態(tài)。那任何線程又可以競爭上崗了。第二節(jié):Mutex互斥對象對互斥量的注意點(diǎn):1、線程id和遞歸計(jì)數(shù)器遞增只能在wait函數(shù)中進(jìn)行操作;2、必須要主要調(diào)用release函數(shù),否則會一直遞增導(dǎo)致死鎖出現(xiàn)。第三節(jié):編寫UiMultiDemo程序向?qū)蒛iMultiDemo程序創(chuàng)建一個(gè)Win32項(xiàng)目,項(xiàng)目名稱叫UiMultiDemo ,如圖:第三節(jié):編寫UiMultiDemo程序注冊窗口類第三節(jié):編寫UiMultiDe

10、mo程序設(shè)置注冊窗口的位置和大小第三節(jié):編寫UiMultiDemo程序定義窗口處理函數(shù)第三節(jié):編寫UiMultiDemo程序窗口函數(shù)實(shí)現(xiàn)WndProc1、WndProc2、WndProc3、WndPro4函數(shù)定義是一樣的, WndProc1函數(shù)實(shí)現(xiàn)如圖:第三節(jié):編寫UiMultiDemo程序窗口函數(shù)實(shí)現(xiàn)程序效果:第三節(jié):編寫UiMultiDemo程序定義THRPARAMS結(jié)構(gòu)體第三節(jié):編寫UiMultiDemo程序處理WM_CREATE消息第三節(jié):編寫UiMultiDemo程序處理WM_SIZE消息第三節(jié):編寫UiMultiDemo程序編寫線程函數(shù)這個(gè)線程函數(shù)主要功能就是循環(huán)銷售火車票,直到火

11、車票售完為止ThrTicketProc1線程函數(shù)實(shí)現(xiàn)如圖:第三節(jié):編寫UiMultiDemo程序編寫線程函數(shù)這個(gè)線程函數(shù)主要功能就是循環(huán)銷售火車票,直到火車票售完為止ThrTicketProc2線程函數(shù)實(shí)現(xiàn)如圖:第三節(jié):編寫UiMultiDemo程序?yàn)槭裁匆玫組utex同步技術(shù)在這里我們的火車票是一個(gè)全局變量g_trainTickets,兩個(gè)線程都在出售這個(gè)火車票,當(dāng)還有最后一張票時(shí),線程1開始出售時(shí),這時(shí)開始到了睡眠,線程2又開始售票時(shí),又開始睡眠,這時(shí)線程1已經(jīng)醒了,那么開始售票。線程2這個(gè)時(shí)候也醒了,也開始售票,結(jié)果就出售了一張0票,0票顯示是不對的。第三節(jié):編寫UiMultiDemo

12、程序運(yùn)用Mutex怎樣實(shí)現(xiàn)同步在CreateMutex創(chuàng)建互斥對象的時(shí)候,第二個(gè)參數(shù)我們傳的是FALSE。那么就表示當(dāng)前線程沒有擁有這個(gè)互斥對象,操作系統(tǒng)就會把這個(gè)互斥對象設(shè)為有信號狀態(tài),那么ThrTicketProc1線程就可以開始售票了,ThrTicketProc1在遇到Sleep函數(shù)時(shí)開始睡眠,接著ThrTicketProc2線程開始運(yùn)行,但是因?yàn)闆]有信號,所以著ThrTicketProc2線程繼續(xù)等待,這個(gè)時(shí)候ThrTicketProc1線程醒來,并且售完了一張票,之后,調(diào)用ReleaseMutex函數(shù)釋放所有權(quán),那么互斥對象又變?yōu)橛行盘柕牧?,輪到ThrTicketProc2線程時(shí)就可

13、以售票了。第三節(jié):編寫UiMultiDemo程序處理WM_DESTROY消息和WM_PAINT消息第四節(jié):臨界區(qū)(Critical Section)Win32之中最容易使用的一個(gè)同步機(jī)制就是critical section。某些共享資源具有互斥性,也就是它要求被互斥地使用 ,在任何時(shí)刻都只能有一個(gè)線程使用它。在程序中最常見的是全局變量的互斥使用和緩沖區(qū)的互斥使用。臨界區(qū)的出現(xiàn)形式是一小段代碼,這一小段代碼中包含互斥資源。臨界區(qū)也有一定的局限性:它只能用于同步單個(gè)進(jìn)程中的線程。在這里大家得注意一點(diǎn)就是:“在任何的關(guān)于同步機(jī)制中,不論是在哪一個(gè)操作系統(tǒng)下,我們都不要長時(shí)間鎖住一份資源”。如果你一直

14、讓資源被鎖定,你就會阻止其他線程的執(zhí)行,并把整個(gè)程序帶到一個(gè)完全停止的狀態(tài),我們很難定義所謂“長時(shí)間”是多長,但是我能夠給你的最可靠的建議就是,不要在一個(gè)critical section中調(diào)用Sleep()或任何Wait.()等待之類的API函數(shù) 第四節(jié):臨界區(qū)(Critical Section)InitializeCriticalSection 函數(shù)初始化一個(gè)臨界區(qū)對象VOID InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection / critical section);lpCriticalSection 臨界資源對象指

15、針第四節(jié):臨界區(qū)(Critical Section)DeleteCriticalSection函數(shù)通過一個(gè)臨界區(qū)對象來釋放所有的資源,使得不在擁有這個(gè)對象void DeleteCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);lpCriticalSection 指向一個(gè)不再需要的 CRITICAL_SECTION 變量第四節(jié):臨界區(qū)(Critical Section)EnterCriticalSection 函數(shù)進(jìn)入臨界區(qū)void EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSect

16、ion); lpCriticalSection 臨界資源對象指針第四節(jié):臨界區(qū)(Critical Section)LeaveCriticalSection函數(shù)離開臨界區(qū)void LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection); lpCriticalSection 臨界資源對象指針第四節(jié):臨界區(qū)(Critical Section)第五節(jié):算術(shù)程序定義靜態(tài)的THRPARAMS結(jié)構(gòu)體變量在WndProc2函數(shù)里定義thrParams2靜態(tài)變量static THRPARAMS thrParams2;第五節(jié):算術(shù)程序處理WM_CREA

17、TE消息第五節(jié):算術(shù)程序處理WM_SIZE消息第五節(jié):算術(shù)程序編寫線程函數(shù)ThrCalcProc1線程循環(huán)出加法題g_subjectNum全局變量設(shè)置了總共有多少題每出一道題,g_subjectNum減1,當(dāng)g_subjectNum值為0時(shí),線程退出 第五節(jié):算術(shù)程序編寫線程函數(shù)ThrCalcProc2線程循環(huán)出減法題g_subjectNum全局變量設(shè)置了總共有多少題每出一道題,g_subjectNum減1,當(dāng)g_subjectNum值為0時(shí),線程退出 第五節(jié):算術(shù)程序處理WM_PAINT消息和WM_DESTROY消息第六節(jié):事件(Event)事件內(nèi)核對象包含 1、 一個(gè)使用計(jì)數(shù)器 2、一個(gè)表

18、示事件是否是自動重置還是手動重置的布爾值 3、一個(gè)表示事件有沒有被觸發(fā)的布爾值 4、當(dāng)觸發(fā)為true時(shí),等待該事件的線程變?yōu)榭烧{(diào)度狀態(tài) 5、事件的觸發(fā)表示一個(gè)操作已經(jīng)完成第六節(jié):事件(Event)CreateEvent函數(shù)HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes,/ 安全屬性BOOL bManualReset,/ 復(fù)位方式BOOL bInitialState,/ 初始狀態(tài)LPCTSTR lpName / 對象名稱);第六節(jié):事件(Event)CreateEvent函數(shù)lpEventAttributes 一個(gè)指向SECU

19、RITY_ATTRIBUTES結(jié)構(gòu)的指針,確定返回的句柄是否可被子進(jìn)程繼承。 如果lpEventAttributes是NULL,此句柄不能被繼承bManualReset 指定將事件對象創(chuàng)建成手動復(fù)原還是自動復(fù)原。如果是TRUE,那么必須用ResetEvent函數(shù)來 手工將事件的狀態(tài)復(fù)原 到無信號狀態(tài)。如果設(shè)置為FALSE,當(dāng)事件被一個(gè)等待線程釋放以后,系統(tǒng)將會自動將事件狀態(tài)復(fù)原為無信號狀 態(tài)。bInitialState 指定事件對象的初始狀態(tài)。如果為TRUE,初始狀態(tài)為有信號狀態(tài);否則為無信號狀態(tài)。第六節(jié):事件(Event)CreateEvent函數(shù)lpName 指定事件的對象的名稱,是一個(gè)以

20、0結(jié)束的字符串指針。名稱的字符格式限定在MAX_PATH之內(nèi)。名 字是對大小寫敏感的。 如果lpName指定的名字,與一個(gè)存在的命名的事件對象的名稱相同,函數(shù)將請求EVENT_ALL_ACCESS來訪問 存在的對象。這時(shí)候, 由于bManualReset和bInitialState參數(shù)已經(jīng)在創(chuàng)建事件的進(jìn)程中設(shè)置,這兩個(gè)參數(shù)將被忽略。如果 lpEventAttributes是參數(shù)不是 NULL,它將確定此句柄是否可以被繼承,但是其安全描述符成員將被忽略。 如果lpName為NULL,將創(chuàng)建一個(gè)無名的事件對象第六節(jié):事件(Event)SetEvent函數(shù)設(shè)置事件對象為有信號狀態(tài)BOOL SetEv

21、ent(HANDLE hEvent);hEvent 設(shè)置事件對象的句柄第六節(jié):事件(Event)ResetEvent函數(shù)設(shè)置事件對象為無信號BOOL ResetEvent(HANDLE hEvent);hEvent 設(shè)置事件對象的句柄第七節(jié):小球程序定義靜態(tài)的THRPARAMS結(jié)構(gòu)體變量WndProc3中定義一個(gè)靜態(tài)的thrParams3結(jié)構(gòu)體變量 static THRPARAMS thrParams3;第七節(jié):小球程序處理WM_CREATE消息第七節(jié):小球程序處理WM_SIZE消息第七節(jié):小球程序編寫編程函數(shù)hrBallProc1線程畫一個(gè)綠色小球第七節(jié):小球程序編寫編程函數(shù)hrBallPr

22、oc2線程畫一個(gè)紅色小球截圖:第七節(jié):小球程序編寫編程函數(shù)hrBallProc3線程畫一個(gè)藍(lán)色小球截圖:第七節(jié):小球程序怎樣通過事件對象實(shí)現(xiàn)同步在WM_CREATEA消息里,我們首先創(chuàng)建了一個(gè)有信號的事件對象(g_hEvent1)和兩個(gè)初始為無信號的事件對象g_hEvent2、g_hEvent3。當(dāng)ThrBallProc1線程運(yùn)行的時(shí)候,此時(shí)g_hEvent1事件對象是有信號的,所以可以執(zhí)行里面的代碼,而ThrBallProc2線程、ThrBallProc3線程里的g_hEvent2、g_hEvent3事件對象此時(shí)是無信號的,因此線程只能掛起,當(dāng)ThrBallProc1線程運(yùn)行完后,會調(diào)用Se

23、tEvent來設(shè)置哪個(gè)事件是有信號的,此時(shí)是g_hEvent2事件對象,然后ThrBallProc2線程就能開始運(yùn)行。之后等到ThrBallProc2線程運(yùn)行完畢就設(shè)置g_hEvent3事件為有信號,因此ThrBallProc3線程得以運(yùn)行 第七節(jié):小球程序處理WM_PAINT消息WM_DESTROY消息第八節(jié):Semaphore信號對象1、假設(shè)有5個(gè)位置。而外面有很多人要進(jìn)來。那么當(dāng)5個(gè)位置被人占用了后,其他人就必須排隊(duì)等待。每個(gè)人使用時(shí)間不同,5個(gè)占用的位置,其中有兩個(gè)完成了,那么排隊(duì)的人中最前面的兩個(gè)人進(jìn)行可以使用,但是最多就是5個(gè)人同時(shí)能夠使用。這就是信號量。2、例如我們在服務(wù)器中創(chuàng)建

24、了一個(gè)線程池,它由5個(gè)線程組成。也就意味著最多同時(shí)處理5個(gè)請求,一旦超過5個(gè),那么請求就放入緩存中。當(dāng)一個(gè)或多個(gè)請求(最多5個(gè))完成后,那么從緩存中拿出其他的請求再進(jìn)行處理。第八節(jié):Semaphore信號對象1、信號量用來對資源進(jìn)行計(jì)數(shù)2、包含一個(gè)使用計(jì)數(shù)器,一個(gè)最大資源計(jì)數(shù)器,和一個(gè)當(dāng)前資源計(jì)數(shù)器3、最大資源計(jì)數(shù)器用來控制最大的資源數(shù)。4、當(dāng)前資源計(jì)數(shù)器表示當(dāng)前可用的資源數(shù)量第八節(jié):Semaphore信號對象規(guī)則: 1、如果當(dāng)前資源0,則信號量處于觸發(fā)狀態(tài) 2、如果當(dāng)前資源=0, 則信號量處于未觸發(fā)狀態(tài) 3、系統(tǒng)絕對不會讓當(dāng)前資源計(jì)數(shù)變?yōu)樨?fù)值 4、當(dāng)前資源計(jì)數(shù)絕對不會大于最大資源計(jì)數(shù)第八節(jié):Semaphore信號對象流程:1、假設(shè)我們創(chuàng)建了一個(gè)信號量,它的最大資源計(jì)數(shù)為5,且當(dāng)前資源計(jì)數(shù)也為5(一般都是在初始化過程中間最大資源計(jì)數(shù)值和當(dāng)前資源計(jì)數(shù)值設(shè)置為相同).由于當(dāng)前資源計(jì)數(shù)器大于0,說明信號量處于觸發(fā)狀態(tài)。 2、為了獲取對被保護(hù)的資源的訪問權(quán),線程會調(diào)用w

溫馨提示

  • 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)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論