多任務(wù)、多進(jìn)程和多線程
Windows95和WindowsNT操作系統(tǒng)支持多任務(wù)調(diào)度和處理,由此提供了多任務(wù)空間。程序員可控制應(yīng)用程序中每一個片段的運行,從而編寫高效率的應(yīng)用程序。
所謂多任務(wù)通常包括兩大類:多進(jìn)程和多線程。進(jìn)程是指在系統(tǒng)中正在運行的一個應(yīng)用程序;線程是系統(tǒng)分配處理器時間資源的基本單元,或者說進(jìn)程之內(nèi)獨立執(zhí)行的一個單元。對于操作系統(tǒng)而言,其調(diào)度單元是線程。一個進(jìn)程至少包括一個線程,通常將該線程稱為主線程。一個進(jìn)程從主線程的執(zhí)行開始進(jìn)而創(chuàng)建一個或多個附加線程,這就是所謂基于多線程的多任務(wù)。
開發(fā)多線程應(yīng)用程序可利用32位Windows環(huán)境提供的Win32API接口函數(shù),也可利用VC++中提供的MFC類庫。多線程編程在這兩種方式下原理是一樣的,用戶可以根據(jù)需要選擇相應(yīng)的工具。本文重點講述用VC++5提供的MFC類庫實現(xiàn)多線程調(diào)度與處理的方法,以及由線程多任務(wù)所引發(fā)的同步多任務(wù)特征,并給出一個實現(xiàn)多線程的例程。
基于MFC的多線程編程
1.MFC對多線程的支持
MFC類庫提供了多線程編程支持,使用戶編程更加方便。重要的是,在多窗口線程情況下,MFC直接提供了用戶接口線程的設(shè)計。
MFC區(qū)分兩種類型的線程:輔助線程(WorkerThread)和用戶界面線程(UserInterfaceThread)。輔助線程沒有消息機(jī)制,通常用來執(zhí)行后臺計算和維護(hù)任務(wù)。MFC為用戶界面線程提供消息機(jī)制,用來處理用戶的輸入,響應(yīng)用戶產(chǎn)生的事件和消息。但對于Win32的API來說,這兩種線程并沒有區(qū)別,它只需要線程的啟動地址以便啟動線程執(zhí)行任務(wù)。用戶界面線程的一個典型應(yīng)用就是CWinApp類,它是CWinThread類的派生類,提供應(yīng)用程序的主線程,并負(fù)責(zé)處理用戶產(chǎn)生的事件和消息。CWinThread類是用戶接口線程的基本類,其對象用以維護(hù)特定線程的局部數(shù)據(jù)。因為處理線程局部數(shù)據(jù)依賴于CWinThread類,所以所有使用MFC的線程都必須由MFC來創(chuàng)建。例如,由run-time函數(shù)_beginthreadex創(chuàng)建的線程就不能使用任何MFCAPI。
2.輔助線程和用戶界面線程的創(chuàng)建和終止
要創(chuàng)建一個線程,需要調(diào)用函數(shù)AfxBeginThread。該函數(shù)因參數(shù)重載不同而具有兩種版本,分別對應(yīng)輔助線程和用戶界面線程。無論是輔助線程還是用戶界面線程,都需要指定額外的參數(shù)以修改優(yōu)先級、堆棧大小、創(chuàng)建標(biāo)志和安全特性等。函數(shù)AfxBeginThread返回指向CWinThread類對象的指針。
創(chuàng)建助手線程相對簡單,只需實現(xiàn)控制函數(shù)和啟動線程,而不必從CWinThread派生一個類。簡要說明如下:
(1)實現(xiàn)控制函數(shù)。控制函數(shù)定義該線程。當(dāng)進(jìn)入該函數(shù),線程啟動;退出時,線程終止。該控制函數(shù)聲明如下:
UINTMyControllingFunction(LPVOIDpParam);
該參數(shù)是一個單精度32位值。該參數(shù)接收的值將在線程對象創(chuàng)建時傳遞給構(gòu)造函數(shù),控制函數(shù)將用某種方式解釋該值。它可以是數(shù)量值,或是指向包括多個參數(shù)的結(jié)構(gòu)的指針,甚至可以忽略。如果該參數(shù)是指結(jié)構(gòu),則不僅可以將數(shù)據(jù)從調(diào)用函數(shù)傳給線程,也可以從線程回傳給調(diào)用函數(shù)。如果使用這樣的結(jié)構(gòu)回傳數(shù)據(jù),當(dāng)結(jié)果準(zhǔn)備好時,線程要通知調(diào)用函數(shù);當(dāng)函數(shù)結(jié)束時,應(yīng)返回一個UINT類型的值,指明結(jié)束的原因。通常,返回0表明成功,其他值分別代表不同的錯誤。
(2)啟動線程。由函數(shù)AfxBeginThread創(chuàng)建并初始化一個CWinThread類的對象,啟動并返回該線程的地址,則線程進(jìn)入運行狀態(tài)。
下面用簡單的代碼說明怎樣定義一個控制函數(shù)以及如何在程序的其他部分使用。
UINTMyThreadProc(LPVOIDpParam)
{
CMyObject*pObject=(CMyObject*)pParam;
if(pObject==NULL||!pObject->IsKindOf(RUNTIME_CLASS(CMyObject)))
return-1;//非法參數(shù)
……//具體實現(xiàn)內(nèi)容
return0;//線程成功結(jié)束
}
//在程序中調(diào)用線程的函數(shù)
……
pNewObject=newCMyObject;
AfxBeginThread(MyThreadProc,pNewObject);
……
Windows95和WindowsNT操作系統(tǒng)支持多任務(wù)調(diào)度和處理,由此提供了多任務(wù)空間。程序員可控制應(yīng)用程序中每一個片段的運行,從而編寫高效率的應(yīng)用程序。
所謂多任務(wù)通常包括兩大類:多進(jìn)程和多線程。進(jìn)程是指在系統(tǒng)中正在運行的一個應(yīng)用程序;線程是系統(tǒng)分配處理器時間資源的基本單元,或者說進(jìn)程之內(nèi)獨立執(zhí)行的一個單元。對于操作系統(tǒng)而言,其調(diào)度單元是線程。一個進(jìn)程至少包括一個線程,通常將該線程稱為主線程。一個進(jìn)程從主線程的執(zhí)行開始進(jìn)而創(chuàng)建一個或多個附加線程,這就是所謂基于多線程的多任務(wù)。
開發(fā)多線程應(yīng)用程序可利用32位Windows環(huán)境提供的Win32API接口函數(shù),也可利用VC++中提供的MFC類庫。多線程編程在這兩種方式下原理是一樣的,用戶可以根據(jù)需要選擇相應(yīng)的工具。本文重點講述用VC++5提供的MFC類庫實現(xiàn)多線程調(diào)度與處理的方法,以及由線程多任務(wù)所引發(fā)的同步多任務(wù)特征,并給出一個實現(xiàn)多線程的例程。
基于MFC的多線程編程
1.MFC對多線程的支持
MFC類庫提供了多線程編程支持,使用戶編程更加方便。重要的是,在多窗口線程情況下,MFC直接提供了用戶接口線程的設(shè)計。
MFC區(qū)分兩種類型的線程:輔助線程(WorkerThread)和用戶界面線程(UserInterfaceThread)。輔助線程沒有消息機(jī)制,通常用來執(zhí)行后臺計算和維護(hù)任務(wù)。MFC為用戶界面線程提供消息機(jī)制,用來處理用戶的輸入,響應(yīng)用戶產(chǎn)生的事件和消息。但對于Win32的API來說,這兩種線程并沒有區(qū)別,它只需要線程的啟動地址以便啟動線程執(zhí)行任務(wù)。用戶界面線程的一個典型應(yīng)用就是CWinApp類,它是CWinThread類的派生類,提供應(yīng)用程序的主線程,并負(fù)責(zé)處理用戶產(chǎn)生的事件和消息。CWinThread類是用戶接口線程的基本類,其對象用以維護(hù)特定線程的局部數(shù)據(jù)。因為處理線程局部數(shù)據(jù)依賴于CWinThread類,所以所有使用MFC的線程都必須由MFC來創(chuàng)建。例如,由run-time函數(shù)_beginthreadex創(chuàng)建的線程就不能使用任何MFCAPI。
2.輔助線程和用戶界面線程的創(chuàng)建和終止
要創(chuàng)建一個線程,需要調(diào)用函數(shù)AfxBeginThread。該函數(shù)因參數(shù)重載不同而具有兩種版本,分別對應(yīng)輔助線程和用戶界面線程。無論是輔助線程還是用戶界面線程,都需要指定額外的參數(shù)以修改優(yōu)先級、堆棧大小、創(chuàng)建標(biāo)志和安全特性等。函數(shù)AfxBeginThread返回指向CWinThread類對象的指針。
創(chuàng)建助手線程相對簡單,只需實現(xiàn)控制函數(shù)和啟動線程,而不必從CWinThread派生一個類。簡要說明如下:
(1)實現(xiàn)控制函數(shù)。控制函數(shù)定義該線程。當(dāng)進(jìn)入該函數(shù),線程啟動;退出時,線程終止。該控制函數(shù)聲明如下:
UINTMyControllingFunction(LPVOIDpParam);
該參數(shù)是一個單精度32位值。該參數(shù)接收的值將在線程對象創(chuàng)建時傳遞給構(gòu)造函數(shù),控制函數(shù)將用某種方式解釋該值。它可以是數(shù)量值,或是指向包括多個參數(shù)的結(jié)構(gòu)的指針,甚至可以忽略。如果該參數(shù)是指結(jié)構(gòu),則不僅可以將數(shù)據(jù)從調(diào)用函數(shù)傳給線程,也可以從線程回傳給調(diào)用函數(shù)。如果使用這樣的結(jié)構(gòu)回傳數(shù)據(jù),當(dāng)結(jié)果準(zhǔn)備好時,線程要通知調(diào)用函數(shù);當(dāng)函數(shù)結(jié)束時,應(yīng)返回一個UINT類型的值,指明結(jié)束的原因。通常,返回0表明成功,其他值分別代表不同的錯誤。
(2)啟動線程。由函數(shù)AfxBeginThread創(chuàng)建并初始化一個CWinThread類的對象,啟動并返回該線程的地址,則線程進(jìn)入運行狀態(tài)。
下面用簡單的代碼說明怎樣定義一個控制函數(shù)以及如何在程序的其他部分使用。
UINTMyThreadProc(LPVOIDpParam)
{
CMyObject*pObject=(CMyObject*)pParam;
if(pObject==NULL||!pObject->IsKindOf(RUNTIME_CLASS(CMyObject)))
return-1;//非法參數(shù)
……//具體實現(xiàn)內(nèi)容
return0;//線程成功結(jié)束
}
//在程序中調(diào)用線程的函數(shù)
……
pNewObject=newCMyObject;
AfxBeginThread(MyThreadProc,pNewObject);
……