C 多任務(wù)與多線程編程_第1頁
C 多任務(wù)與多線程編程_第2頁
C 多任務(wù)與多線程編程_第3頁
C 多任務(wù)與多線程編程_第4頁
C 多任務(wù)與多線程編程_第5頁
已閱讀5頁,還剩80頁未讀 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

會計學(xué)1C多任務(wù)與多線程編程第16章多任務(wù)與多線程編程16.1程序、進(jìn)程和線程概述16.2線程的種類16.3線程的創(chuàng)建、啟動和終止16.4線程的操作和管理16.5在VC++環(huán)境中使用同步對象16.6本章小結(jié)16.7思考與練習(xí)第2頁/共85頁第1頁/共85頁16.1程序、進(jìn)程和線程概述16.1.1多任務(wù)、進(jìn)程和線程1.Windows3.x的協(xié)同多任務(wù)如何解決后臺工作和對用戶的隨時響應(yīng)之間的協(xié)同?詳見教材P27。Windows3.x對應(yīng)用程序的CPU控制權(quán)的調(diào)度方式:協(xié)同式多任務(wù)。其特點詳見教材P27。

補(bǔ)充知識:什么是模態(tài)對話框和非模態(tài)對話框?

見附帶文件1。第3頁/共85頁第2頁/共85頁16.Windows95/NT的搶先式多任務(wù)Windows95/NT對應(yīng)用程序的CPU控制權(quán)的調(diào)度方式:搶先式多任務(wù)。其特點詳見教材P28。16.1.1多任務(wù)、進(jìn)程和線程第4頁/共85頁第3頁/共85頁3.進(jìn)程與線程16.1.1多任務(wù)、進(jìn)程和線程進(jìn)程由私有虛擬地址空間、代碼、數(shù)據(jù)和其它操作系統(tǒng)資源(如進(jìn)程創(chuàng)建的文件、同步對象等)組成。

進(jìn)程就是應(yīng)用程序的運(yùn)行實例。1)什么是進(jìn)程?一個應(yīng)用程序可以運(yùn)行一個或多個進(jìn)程。多任務(wù)就是指操作系統(tǒng)可以同時運(yùn)行多個進(jìn)程。第5頁/共85頁第4頁/共85頁16.1.1多任務(wù)、進(jìn)程和線程2)什么是線程?一個線程可以執(zhí)行程序的任意部分的代碼,即使這部分代碼被另一個線程并發(fā)地執(zhí)行。線程是Windows95/NT操作系統(tǒng)分時調(diào)度中分配CPU時間的基本單位。第6頁/共85頁第5頁/共85頁一個進(jìn)程可以有一個或多個線程,其中一個是主線程。一個進(jìn)程的所有線程共享它的虛擬地址空間、全局變量和操作系統(tǒng)資源。16.1.1多任務(wù)、進(jìn)程和線程3)進(jìn)程與線程的關(guān)系?第7頁/共85頁第6頁/共85頁16.2線程的種類線程有兩種用戶界面線程工作者線程MFC應(yīng)用程序通過調(diào)用AfxBeginThread函數(shù)并給定不同的參數(shù)來自動創(chuàng)建兩種線程,而不需要程序自己創(chuàng)建,AfxBeginThread函數(shù)的具體說明在16.3.1中。第8頁/共85頁第7頁/共85頁16.16.1MFC中的線程類1.MFC應(yīng)用程序中的線程可由對象CWinThread表示,CWinThread類派生自CcmdTarget類;16.CWinThread對象代表在一個應(yīng)用程序內(nèi)運(yùn)行的線程;3.CWinThread對象允許一個應(yīng)用程序擁有多個線程;4.CWinThread對象支持兩種線程類型:用戶界面線程和工作者線程;第9頁/共85頁第8頁/共85頁16.16.1MFC中的線程類5.

用戶界面線程可以由CWinThread類派生,也可以是CWinApp類或其派生類。但為安全起見,應(yīng)由CWinThread類派生。6.

任何使用MFC的線程必須由MFC創(chuàng)建,創(chuàng)建一個線程必須調(diào)用AfxBeginThread函數(shù)。7.CWinThread類的數(shù)據(jù)成員即成員函數(shù)見表2-1。第10頁/共85頁第9頁/共85頁16.16.2用戶界面線程(UI)1)

用戶界面線程擁有自己的消息循環(huán)來處理界面消息,具有收發(fā)消息的功能,處理從消息隊列取得的消息;2)

用戶界面線程通常要與用戶交互;3)

用戶界面線程可由CWinApp類派生(注:CWinApp類由CWinThread類派生),也可以由CWinThread類直接派生。4)

一個應(yīng)用程序的主線程通常由CWinApp類派生,主線程應(yīng)該是用戶界面線程。第11頁/共85頁第10頁/共85頁16.16.3工作者線程1)

工作者線程沒有自己的消息循環(huán),一般用來完成后臺的工作,如后臺計算、打印、與其它設(shè)備的串行數(shù)據(jù)通信等,這些工作的共同特點就是耗時。2)

為了不影響主線程與用戶的交互,通常耗時的工作交給工作者線程來完成;3)

工作者線程可由CWinThread類直接派生。第12頁/共85頁第11頁/共85頁16.3線程的創(chuàng)建、啟動和終止16.3.1線程的創(chuàng)建線程的創(chuàng)建由AfxBeginThread函數(shù)完成。AfxBeginThread函數(shù)有兩種調(diào)用格式,可以根據(jù)需要分別用來創(chuàng)建工作者線程和用戶界面線程。第13頁/共85頁第12頁/共85頁一、AfxBeginThread函數(shù)用來創(chuàng)建工作者線程的調(diào)用格式:16.3.1線程的創(chuàng)建CWinThread*AfxBeginThread(

AFX_THREADPROCpfnThreadProc,

LPVOIDpParam,

intnPriority=THREAD_PRIORITY_NORMAL,

UINTnStackSize=0,

DWORDdwCreateFlags=0,

LPSECURITY_ATTRIBUTESlpSecurityAttrs=NULL

);第14頁/共85頁第13頁/共85頁pfnThreadProc:線程函數(shù)的地址,該參數(shù)不能設(shè)置為NULL,線程函數(shù)必須定義成全局函數(shù)或者類的靜態(tài)成員函數(shù)。例如:

UINTmyThreadFunc(LPVOIDlparam)

或者

classA

{

public:

staticUINT__stdcallmyThreadFunc(LPVOIDlparam);

}1.參數(shù)說明:16.3.1線程的創(chuàng)建第15頁/共85頁第14頁/共85頁pParam:要傳遞給線程函數(shù)的參數(shù);nPriority:要啟動的線程的優(yōu)先級,默認(rèn)優(yōu)先級為THREAD_PRIORITY_NORMAL(普通優(yōu)先級),關(guān)于線程優(yōu)先級的詳細(xì)說明見16.4.2;nStackSize:新線程的堆棧大小,如果設(shè)置為0,則使用默認(rèn)大小,在應(yīng)用程序中一般情況下線程的默認(rèn)堆棧大小為1M;16.3.1線程的創(chuàng)建第16頁/共85頁第15頁/共85頁lpSecurityAttrs

:指向SECURITY_ATTRIBUTES結(jié)構(gòu)的指針,結(jié)構(gòu)中指定了線程的安全屬性。如果為NULL,則與

創(chuàng)建它的線程的安全屬性相同。dwCreateFlags:線程創(chuàng)建標(biāo)志,該參數(shù)指定線程的初始狀態(tài),它可以被指定為下列標(biāo)志:

0:線程在創(chuàng)建后立即執(zhí)行

CREATE_SUSPENDED:線程在創(chuàng)建后立即掛起16.3.1線程的創(chuàng)建第17頁/共85頁第16頁/共85頁16.函數(shù)返回值的說明:函數(shù)AfxBeginThread返回指向CWinThread類的指針。16.3.1線程的創(chuàng)建第18頁/共85頁第17頁/共85頁3.創(chuàng)建工作者線程的過程:利用函數(shù)AfxBeginThread創(chuàng)建工作者線程需要兩步:1)編寫線程控制函數(shù);2)調(diào)用函數(shù)AfxBeginThread啟動線程,將線程控制函數(shù)的地址作為第一個參數(shù),線程控制函數(shù)的參數(shù)作為第二個參數(shù)賦給AfxBeginThread函數(shù),16.3.1線程的創(chuàng)建第19頁/共85頁第18頁/共85頁在應(yīng)用程序中,可以創(chuàng)建一個指向CWinThread類的指針,用來保存AfxBeginThread函數(shù)的返回值,即AfxBeginThread函數(shù)創(chuàng)建成功的線程類CWinThread,以便創(chuàng)建好的線程進(jìn)行控制,例如:4.其它說明:16.3.1線程的創(chuàng)建第20頁/共85頁第19頁/共85頁CWinThread*pWinThread;pWinThread=AfxBeginThread(

ControlFunction,pParam,THREAD_PRIORTY_NORMAL,0,CREATE_SUSPENDED,NULL);16.3.1線程的創(chuàng)建第21頁/共85頁第20頁/共85頁pWinThread->m_bAutoDelete=false;………………deletepWinThread;這時應(yīng)注意:即要將CWinThread類的數(shù)據(jù)成員m_bAutoDelete設(shè)為false,并且在退出進(jìn)程前,將指向線程類CWinThread的指針pWinThread刪除。16.3.1線程的創(chuàng)建第22頁/共85頁第21頁/共85頁二、AfxBeginThread函數(shù)用來創(chuàng)建用戶界面線程的調(diào)用格式:CWinThread*AfxBeginThread(CRuntimeClass*pThreadClass,intnPriority=THREAD_PRIORITY_NORMAL,UINTnStackSize=0,DWORDdwCreateFlags=0,LPSECURITY_ATTRIBUTESlpSecurityAttrs=NULL

);16.3.1線程的創(chuàng)建第23頁/共85頁第22頁/共85頁pfnThreadProc:指向CRuntimeClass類的指針。其它參數(shù)的說明與前面相同。1.參數(shù)說明:16.創(chuàng)建用戶界面線程的過程:1)從CWinThread類派生一個新類,派生類必須用DECLARE_DYNCREATE和IMPLEMENT_DYNCREATE宏來聲明和實現(xiàn);16.3.1線程的創(chuàng)建第24頁/共85頁第23頁/共85頁2)重載派生類的InitInstance、ExitInstance等函數(shù),在InitInstance函數(shù)中添加代碼。四、通過例題演示利用AfxBeginThread函數(shù)創(chuàng)建工作者線程和用戶界面線程的過程。16.3.1線程的創(chuàng)建三、關(guān)于CreateThread()函數(shù)的一些說明:見附帶文件2。第25頁/共85頁第24頁/共85頁16.3.2線程的啟動線程啟動時的初始狀態(tài)可以通過AfxBeginThread()函數(shù)的dwCreateFlags參數(shù)指定。如下:0:線程在創(chuàng)建后立即執(zhí)行;CREATE_SUSPENDED:線程在創(chuàng)建后立即掛起;所謂掛起就是暫停線程的執(zhí)行。第26頁/共85頁第25頁/共85頁16.3.3線程的終止遇到以下情況時,線程終止執(zhí)行:1.線程控制函數(shù)返回(即執(zhí)行了return語句)。16.線程自身調(diào)用函數(shù)ExitThread()函數(shù)即終止自己。該函數(shù)的原型如下:

VOIDWINAPIExitThread(DWORDdwExitCode);

該函數(shù)通過參數(shù)dwExitCode給線程設(shè)置退出碼后,即終止線程的執(zhí)行。第27頁/共85頁第26頁/共85頁16.3.3線程的終止3.同一進(jìn)程或其他進(jìn)程的線程調(diào)用TerminateThread函數(shù),其原型為:BOOLTerminateThread(HANDLEhThread,DWORDdwExitCode);

該函數(shù)用來結(jié)束由hThread參數(shù)指定的線程,并把dwExitCode設(shè)成該線程的退出碼。當(dāng)某個線程不再響應(yīng)時,我們可以用其他線程調(diào)用該函數(shù)來終止這個不響應(yīng)的線程。第28頁/共85頁第27頁/共85頁16.3.3線程的終止4.包含線程的進(jìn)程被終止,如其它進(jìn)程調(diào)用TerminateProcess函數(shù)終止進(jìn)程的執(zhí)行,或進(jìn)程自身調(diào)用ExitProcess函數(shù)終止自身的執(zhí)行。BOOLWINAPITerminateProcess(HANDLEhProcess,UINTuExitCode);

TerminateProcess函數(shù)的原型為:第29頁/共85頁第28頁/共85頁VOIDWINAPIExitProcess(UINTuExitCode);ExitProcess函數(shù)的原型為:16.3.3線程的終止5.

調(diào)用全局函數(shù)AfxEndThread終止進(jìn)程;注意:最好使用第1種方式終止線程,第2~4種方式都不宜采用。第30頁/共85頁第29頁/共85頁16.4.1線程的運(yùn)行狀態(tài)的設(shè)置16.4線程的操作和管理1.當(dāng)參數(shù)dwCreateFlags置為0時,調(diào)用AfxBeginThread函數(shù)創(chuàng)建的線程一啟動就立即執(zhí)行。這時,如果想暫停該線程的執(zhí)行,可調(diào)用其成員函數(shù)SuspendedThread()函數(shù)將自身掛起。AfxEndThread函數(shù)的dwCreateFlags參數(shù)是決定線程在創(chuàng)建時的運(yùn)行狀態(tài)的。第31頁/共85頁第30頁/共85頁16.4.1線程的運(yùn)行狀態(tài)的設(shè)置16.當(dāng)參數(shù)dwCreateFlags置為CREATE_SUSPENDED時,調(diào)用AfxBeginThread函數(shù)創(chuàng)建的線程一啟動就掛起,暫停執(zhí)行。這時,如果想繼續(xù)執(zhí)行線程,可調(diào)用成員函數(shù)ResumeThread()函數(shù)喚醒被掛起的線程。被掛起的線程不能調(diào)用此函數(shù)喚醒自身,必須由一個未被掛起的處于運(yùn)行狀態(tài)的線程調(diào)用此函數(shù)來取消掛起。注意:第32頁/共85頁第31頁/共85頁16.4.2線程的優(yōu)先級一、

Windows操作系統(tǒng)是根據(jù)進(jìn)程和線程的優(yōu)先級來確定它們的排隊順序并分配CPU時間的,所以對于進(jìn)程和線程在其創(chuàng)建時要設(shè)置優(yōu)先級。二、線程的優(yōu)先級是根據(jù)其創(chuàng)建時設(shè)置的優(yōu)先級和擁有該線程的進(jìn)程的優(yōu)先級來確定的。其最終的優(yōu)先級是0到31之間的數(shù)值,數(shù)值越大,優(yōu)先級越高。其中,0~15級是普通優(yōu)先級,16~

30級是實時優(yōu)先級。第33頁/共85頁第32頁/共85頁16.4.2線程的優(yōu)先級Windows操作系統(tǒng)對具有普通優(yōu)先級的線程的調(diào)度特點是:高優(yōu)先級線程先運(yùn)行,只有高優(yōu)先級線程不運(yùn)行時,才調(diào)度低優(yōu)先級線程運(yùn)行。優(yōu)先級相同的線程按照時間片輪流運(yùn)行。三、Windows操作系統(tǒng)對線程的調(diào)度特點第34頁/共85頁第33頁/共85頁16.4.2線程的優(yōu)先級四、Windows操作系統(tǒng)對具有實時優(yōu)先級的線程的調(diào)度特點是:高優(yōu)先級線程先運(yùn)行,只有高優(yōu)先級線程不運(yùn)行時,才調(diào)度低優(yōu)先級線程運(yùn)行。優(yōu)先級相同的線程不按照時間片輪轉(zhuǎn),而是先運(yùn)行的線程就先控制CPU,如果它不主動放棄控制,同級或低優(yōu)先級的線程就無法運(yùn)行。第35頁/共85頁第34頁/共85頁16.4.2線程的優(yōu)先級五、用函數(shù)AfxBeginThread創(chuàng)建線程時,其參數(shù)nPriority指定新線程的優(yōu)先級,該參數(shù)的取值為以下七個值之一:THREAD_PRIORITY_TIME_CRITICALTHREAD_PRIORITY_HIGHESTTHREAD_PRIORITY_ABOVE_NORMALTHREAD_PRIORITY_NORMALTHREAD_PRIORITY_BELOW_NORMALTHREAD_PRIORITY_LOWESTTHREAD_PRIORITY_IDLE第36頁/共85頁第35頁/共85頁16.4.2線程的優(yōu)先級對這七個值的說明,及線程最終優(yōu)先級的確定:見附帶文件3。六、如何改變線程的優(yōu)先級?在應(yīng)用程序中,如果需要改變線程的優(yōu)先級,可以通過線程類的成員函數(shù)SetThreadPriority()對線程的優(yōu)先級重新設(shè)置。其原型如下:

BOOLSetThreadPriority(intnPriority)成功執(zhí)行后返回非零值,不成功返回0。第37頁/共85頁第36頁/共85頁16.4.2線程的優(yōu)先級七、如何獲得線程的優(yōu)先級?在應(yīng)用程序中,有時需要查詢線程的優(yōu)先級,這時可以通過線程類的成員函數(shù)GetThreadPriority()獲得線程的優(yōu)先級。其原型如下:

intGetThreadPriority(HANDLEhThread)

返回THREAD_PRIORITY_ERROR_RETURN表示失敗。成功時返回優(yōu)先級的七個值。第38頁/共85頁第37頁/共85頁16.4.2線程的優(yōu)先級八、Windows動態(tài)調(diào)度線程的說明線程的優(yōu)先級不是一直不變的,Windows操作系統(tǒng)對線程從優(yōu)先級進(jìn)行動態(tài)調(diào)整,以保證所有的線程都能較好的運(yùn)行。當(dāng)線程長時間掛起以等待激活它再次運(yùn)行的信號時,比它優(yōu)先級低的線程將難以得到所需的CPU時間。這種情況下,當(dāng)如果某線程在一段時間沒有運(yùn)行,Windows操作系統(tǒng)將提高它的優(yōu)先級以保證其獲得CPU時間。第39頁/共85頁第38頁/共85頁16.4.3線程間的通信一、用簡單的布爾型變量實現(xiàn)線程間的通信見P40例題二、通過消息的發(fā)送和處理來實現(xiàn)線程和主程序之間的通信1.調(diào)用::PostMessage(),其原型為:第40頁/共85頁第39頁/共85頁16.4.3線程間的通信BOOL

PostMessage(

HWND

hWnd,

//要發(fā)送到的窗口的句柄

UINT

Msg,

//消息的ID值WPARAM

wParam,//消息的第一個參數(shù)

LPARAM

lParam//消息的第二個參數(shù));如果執(zhí)行成功返回非零值,不成功返回0。第41頁/共85頁第40頁/共85頁16.4.3線程間的通信實現(xiàn)方法:1)在頭文件中定義一個消息,如線程終止的消息:

constWM_THREADENDEDWM_USER+102)加入相應(yīng)的消息處理函數(shù)的聲明:

afx_msgLONGOnThreadended(

WPARAMwParam,

LPARAMlParam);第42頁/共85頁第41頁/共85頁16.4.3線程間的通信3)在實現(xiàn)文件中,在消息映射部分,加入消息映射:

ON_MESSGAE(WM_THREADENDED,OnThreadended)4)在線程中使用PostMessage()函數(shù):

PostMessage((HWND)pParam,WM_THREADENDED,0,0)這個語句激活相應(yīng)的消息處理函數(shù),對WM_THREADENDED消息進(jìn)行處理第43頁/共85頁第42頁/共85頁16.4.3線程間的通信16.調(diào)用CWinThread::PostThreadMessage(),其原型為:BOOLPostThreadMessage(UINTmessage,//消息的ID值WPARAMwParam,//消息的第一個參數(shù)

LPARAMlParam//消息的第二個參數(shù));如果執(zhí)行成功返回非零值,不成功返回0。第44頁/共85頁第43頁/共85頁三、使用同步類來實現(xiàn)線程之間的通信和控制在16.5小節(jié)中將詳細(xì)介紹16.4.3線程間的通信第45頁/共85頁第44頁/共85頁16.5在VC++環(huán)境中使用同步對象16.一個進(jìn)程的所有線程共享它的虛擬地址空間、全局變量和操作系統(tǒng)資源。為什么要使用同步對象?1.進(jìn)程由私有虛擬地址空間、代碼、數(shù)據(jù)和其它操作系統(tǒng)資源(如進(jìn)程創(chuàng)建的文件、同步對象等)組成。3.如果對多個線程之間的資源訪問不加以同步控制,這些線程在共享資源時,容易產(chǎn)生訪問沖突,產(chǎn)生不正確的結(jié)果。第46頁/共85頁第45頁/共85頁16.5在VC++環(huán)境中使用同步對象例如在數(shù)據(jù)庫應(yīng)用程序中,需要同時存在兩個線程,一個負(fù)責(zé)讀數(shù)據(jù),一個負(fù)責(zé)寫數(shù)據(jù)。這時就要謹(jǐn)防兩個線程同時對數(shù)據(jù)進(jìn)行操作。這時如果不進(jìn)行同步控制,讀線程所讀取的數(shù)據(jù),其狀態(tài)是不確定的。所以當(dāng)有兩個或多個線程在共享數(shù)據(jù)時,要使用同步對象以確保這多個線程不會同時訪問共享資源。第47頁/共85頁第46頁/共85頁16.5在VC++環(huán)境中使用同步對象CSyncObjectCEventCObjectCCriticalSectionCMutexCSemaphore……MFC中的同步類第48頁/共85頁第47頁/共85頁16.5.1事件對象CEvent類提供了對事件的支持。事件是一個允許一個線程在某種情況發(fā)生時,喚醒另外一個線程的同步對象。事件告訴線程何時去執(zhí)行某一給定的任務(wù),從而使多個線程流平滑。每一個CEvent對象可以有兩種狀態(tài):有信號狀態(tài)(signaled)和無信號狀態(tài)(nonsignaled)。線程監(jiān)視位于其中的CEvent類對象的狀態(tài),并在相應(yīng)的時候采取相應(yīng)的操作。第49頁/共85頁第48頁/共85頁16.5.1事件對象

CEvent類的成員:構(gòu)造函數(shù)CEventPulseEvent函數(shù)Unlock函數(shù)ResetEvent函數(shù)SetEvent函數(shù)下面分別介紹CEvent類的這些成員函數(shù)。第50頁/共85頁第49頁/共85頁16.5.1事件對象1.構(gòu)造函數(shù)CEvent的原型:CEvent(BOOLbInitiallyOwn,BOOLbManualReset,LPCTSTRlpszName,LPSECURITY_ATTRIBUTESlpsaAttribute

)其參數(shù)說明如下:第51頁/共85頁第50頁/共85頁16.5.1事件對象bInitiallyOwn:若bInitiallyOwn為TRUE,則使CMultilock類對象和CSingleLock類對象的線程可用;否則,要訪問資源的線程必須等待。該參數(shù)的默認(rèn)值為FALSE。bManualReset:指定要創(chuàng)建的CEvent對象是屬于手工事件對象還是自動事件對象。若為TRUE,則為手工事件對象,否則為自動事件對象。該參數(shù)默認(rèn)值為FALSE。第52頁/共85頁第51頁/共85頁補(bǔ)充說明:在MFC中,CEvent類對象有兩種類型,分別是所謂的手工事件和自動事件。對于自動事件,當(dāng)其獲得信號后,就會釋放下一個可用的線程。一個自動CEvent對象在被至少一個線程釋放后會自動返回到無信號狀態(tài);而人工事件對象獲得信號后,釋放所有可利用線程,直到調(diào)用成員函數(shù)ReSetEvent()將其設(shè)置為無信號狀態(tài)時為止。

注意:在創(chuàng)建CEvent類的對象時,默認(rèn)創(chuàng)建的是自動事件。16.5.1事件對象第53頁/共85頁第52頁/共85頁16.5.1事件對象lpszName:指定要創(chuàng)建的事件對象的名字,如果該事件對象將跨進(jìn)程使用,則此參數(shù)不能為NULL。如果該參數(shù)和一個已經(jīng)存在的CEvent對象相同,則該構(gòu)造函數(shù)返回一個對這個已存在對象的引用;如果參數(shù)和一個已存在的非CEvent類的同步對象(如CMutex)相同,則對象創(chuàng)建失敗;第54頁/共85頁第53頁/共85頁16.5.1事件對象lpsaAttribute:指向SECURITY_ATTRIBUTES結(jié)構(gòu)的指針,該參數(shù)決定要創(chuàng)建的事件對象的安全屬性,一般置為NULL。第55頁/共85頁第54頁/共85頁16.5.1事件對象16.BOOLSetEvent():將CEvent類對象的狀態(tài)設(shè)置為有信號狀態(tài),并且釋放所有等待的線程;如果該事件是人工事件,則CEvent類對象保持為有信號狀態(tài),直到調(diào)用成員函數(shù)ResetEvent()將其重新設(shè)為無信號狀態(tài)時為止,這樣該事件就可以釋放多個線程;如果CEvent類對象為自動事件,則在SetEvent()將事件設(shè)置為有信號狀態(tài)后,CEvent類對象由系統(tǒng)自動重置為無信號狀態(tài),除非一個線程被釋放。如果該函數(shù)執(zhí)行成功,則返回非零值,否則返回零。第56頁/共85頁第55頁/共85頁16.5.1事件對象3.BOOLResetEvent()該函數(shù)將事件的狀態(tài)設(shè)置為無信號狀態(tài),并保持該狀態(tài)直至SetEvent()被調(diào)用時為止。由于自動事件是由系統(tǒng)自動重置,故自動事件不需要調(diào)用該函數(shù)。如果該函數(shù)執(zhí)行成功,返回非零值,否則返回非零。第57頁/共85頁第56頁/共85頁16.5.1事件對象4.BOOLPulseEvent()

發(fā)送一個事件脈沖,該函數(shù)完成一系列操作后才返回。對于自動事件,PulseEvent()將事件設(shè)置為有信號狀態(tài),等待一個線程被釋放,將事件重置為無信號狀態(tài),然后PulseEvent()返回;對于人工事件,則將等待該事件的所有線程被釋放,事件被自動重置為無信號狀態(tài),然后PulseEvent()返回。一個CEvent對象在線程中被創(chuàng)建后,自動處于無信號狀態(tài),但在另一個線程中可以調(diào)用Win32APIWaitForSingleObject()函數(shù)來監(jiān)視其狀態(tài)。第58頁/共85頁第57頁/共85頁16.5.1事件對象5.BOOLUnlock()如果線程擁有事件對象,并且事件對象是一個自動事件對象,則返回非零值,否則返回0。該函數(shù)用來釋放事件對象,即把Lock鎖定的線程解鎖。第59頁/共85頁第58頁/共85頁16.5.1事件對象另外補(bǔ)充一個函數(shù)BOOLLock()該函數(shù)不是CEvent類的成員函數(shù),是CEvent的父類CSyncObject類的成員函數(shù),CEvent通過繼承可以使用該函數(shù)。該函數(shù)用來鎖定事件對象,阻止線程的繼續(xù)執(zhí)行,直到事件對象處于活動狀態(tài)為止。第60頁/共85頁第59頁/共85頁6.WaitForSingleObject():其原型聲明如下:

DWORDWaitForSingleObject(HANDLEhHandle,DWORDdwMilliseconds)hHandle為指向要監(jiān)視的同步對象的句柄;dwMilliseconds為監(jiān)視hHandle所指向的對象所設(shè)置的超時值,單位為毫秒。16.5.1事件對象第61頁/共85頁第60頁/共85頁當(dāng)在線程的執(zhí)行函數(shù)中調(diào)用該函數(shù)時,線程暫時掛起,系統(tǒng)監(jiān)視hHandle所指向的對象的狀態(tài)。如果經(jīng)過dwMilliseconds毫秒后,hHandle指向的對象變?yōu)橛行盘枲顟B(tài),則WaitForSingleObject()返回,線程被釋放,且返回值為WAIT_TIMEOUT;如果在掛起的dwMilliseconds毫秒內(nèi),線程所等待的對象在某一時刻變?yōu)橛行盘?,則該函數(shù)立即返回,返回值為WAIT_OBJECT_0。16.5.1事件對象第62頁/共85頁第61頁/共85頁參數(shù)dwMilliseconds有兩個具有特殊意義的值:0和INFINITE。若為0,則該函數(shù)立即返回;若為INFINITE,則線程一直被掛起,直到hHandle所指向的對象變?yōu)橛行盘枲顟B(tài)時為止。16.5.1事件對象第63頁/共85頁第62頁/共85頁CEvent::ResetEvent()把對象設(shè)置為無信號狀態(tài),程序在WaitForSingleObject(hHandle,INFINITE)處等待。CEvent::SetEvent()把對象設(shè)置為有信號狀態(tài),釋放等待的線程。如果CEvent對象為自動事件,則當(dāng)WaitForSingleObject(hHandle,INFINITE)返回時,自動把CEvent對象重置為無信號狀態(tài)。16.5.1事件對象總結(jié)以上,幾個函數(shù)的使用順序為:第64頁/共85頁第63頁/共85頁B線程在執(zhí)行到CEvent類成員函數(shù)Lock()時將會發(fā)生阻塞,而A線程此時則可以在沒有B線程干擾的情況下對共享資源進(jìn)行處理,并在處理完成后通過成員函數(shù)SetEvent()向B發(fā)出事件,使其被釋放,得以對A先前已處理完畢的共享資源進(jìn)行操作。16.5.1事件對象另外通過一個例題來演示事件的工作原理:第65頁/共85頁第64頁/共85頁16.5.2臨界區(qū)臨界區(qū)(CriticalSection)是一段代碼,該代碼獨占對某些共享資源的訪問,在任意時刻只允許一個線程對共享資源進(jìn)行訪問。如果有多個線程試圖同時訪問臨界區(qū),那么在有一個線程進(jìn)入后其他所有試圖訪問此臨界區(qū)的線程將被掛起,并一直持續(xù)到進(jìn)入臨界區(qū)的線程離開。臨界區(qū)在被釋放后,其他線程可以繼續(xù)搶占,并以此達(dá)到用原子方式操作共享資源的目的。第66頁/共85頁第65頁/共85頁16.5.2臨界區(qū)在使用臨界區(qū)時,一般不允許其運(yùn)行時間過長,只要進(jìn)入臨界區(qū)的線程還沒有離開,其他所有試圖進(jìn)入此臨界區(qū)的線程都會被掛起而進(jìn)入到等待狀態(tài),并會在一定程度上影響。程序的運(yùn)行性能。尤其需要注意的是不要將等待用戶輸入或是其他一些外界干預(yù)的操作包含到臨界區(qū)。如果進(jìn)入了臨界區(qū)卻一直沒有釋放,同樣也會引起其他線程的長時間等待。第67頁/共85頁第66頁/共85頁16.5.2臨界區(qū)雖然臨界區(qū)同步速度很快,但卻只能用來同步本進(jìn)程內(nèi)的線程,而不可用來同步多個進(jìn)程中的線程。MFC為臨界區(qū)提供有一個CCriticalSection類,使用該類進(jìn)行線程同步處理是非常簡單的,只需在線程函數(shù)中用CCriticalSection類成員函數(shù)Lock()和UnLock()標(biāo)定出被保護(hù)的代碼片段即可。第68頁/共85頁第67頁/共85頁16.5.2臨界區(qū)下面通過一段代碼展示了臨界區(qū)在保護(hù)多線程訪問的共享資源中的作用。通過兩個線程來分別對全局變量g_cArray[10]進(jìn)行寫入操作,用臨界區(qū)對象g_clsCriticalSection來保持線程的同步,并在開啟線程前對其進(jìn)行初始化。為了使實驗效果更加明顯,體現(xiàn)出臨界區(qū)的作用,在線程函數(shù)對共享資源g_cArray[10]的寫入時,以Sleep()函數(shù)延遲1毫秒,使其他線程同其搶占CPU的可能性增大。如果不使用臨界區(qū)對其進(jìn)行保護(hù),則共享資源數(shù)據(jù)將被破壞。而使用臨界區(qū)對線程保持同步后則可以得到正確的結(jié)果。第69頁/共85頁第68頁/共85頁16.5.3互斥量互斥量(Mutex)是一種用途非常廣泛的內(nèi)核對象。能夠保證多個線程對同一共享資源的互斥訪問。同臨界區(qū)有些類似,只有擁有互斥對象的線程才具有訪問資源的權(quán)限,由于互斥對象只有一個,因此就決定了任何情況下此共享資源都不會同時被多個線程所訪問。當(dāng)前占有資源的線程在任務(wù)處理完后應(yīng)將擁有的互斥對象交出,以便其他線程在獲得后得以訪問共享資源。第70頁/共85頁第69頁/共85頁圖:互斥內(nèi)核對象的工作模型16.5.3互斥量與其他幾種內(nèi)核對象不同,互斥對象在操作系統(tǒng)中擁有特殊代碼,并由操作系統(tǒng)來管理,操作系統(tǒng)甚至還允許其進(jìn)行一些其他內(nèi)核對象所不能進(jìn)行的非常規(guī)操作。為便于理解,可參照下圖。共享資源擁有互斥量的線程第71頁/共85頁第70頁/共85頁16.5.3互斥量互斥對象在MFC中通過CMutex類進(jìn)行表述。使用CMutex類的方法非常簡單,在構(gòu)造CMutex類對象的同時可以指明待查詢的互斥對象的名字,在構(gòu)造函數(shù)返回后即可訪問此互斥變量。CMutex類也是只含有構(gòu)造函數(shù)這唯一的成員函數(shù),當(dāng)完成對互斥對象保護(hù)資源的訪問后,可通過調(diào)用從父類CSyncObject繼承的UnLock()函數(shù)完成對互斥對象的釋放。第72頁/共85頁第71頁/共85頁16.5.3互斥量CMutex類構(gòu)造函數(shù)原型為:其參數(shù)說明如下:CMutex(BOOLbInitiallyOwn=FALSE,LPCTSTRlpszName=NULL,LPSECURITY_ATTRIBUTESlpsaAttribute=NULL)第73頁/共85頁第72頁/共85頁16.5.3互斥量bInitiallyOwn:該參數(shù)指定是否創(chuàng)建了CMutex對象的線程最初擁有由互斥量CMutex控制的共享資源的控制權(quán)。第74頁/共85頁第73頁/共85頁16.5.3互斥量lpszName:指定要創(chuàng)建的CMutex對象的名字。若該值為NULL,則生成CMutex

溫馨提示

  • 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

提交評論