(轉貼)關於程式和執行緒 (轉)

gugu99發表於2007-08-15
(轉貼)關於程式和執行緒 (轉)[@more@]筆者最近在開發基於Inte網上的可視電話過程中碰到了這樣一個問題,即在基於In ternet網上的可視電話中,同時要進行語音採集、語音編譯碼、影像採集、影像編譯碼、語音和影像碼流的傳輸,所有這些工作,都要並行處理。特別是語音訊號,如果進行影像編解碼時間過長,語音訊號得不到服務,通話就有間斷;如果影像或語音處理時間過長,而不能及時傳輸碼流資料,通訊同樣也會中斷。這樣就要求我們實現一種並行,在只有一個的機器上,也就是要將該CPU時間按時一定的優先準則分配給各個事件,定期處理各事件,而不會對某一事件處理過長。在32位95或下,我們可以用多執行緒的處理技術來實現這種並行處理。實際上,這種並行程式設計在很多場合下都是必須的。例如,在File Manager複製時,它顯示一個對話方塊中包含了一個Cancel按鈕。如果在檔案複製過程中,點中Cance l按鈕,就會終止複製。在16位Winows中,實現這類功能需要在File Copy迴圈內部週期性地PeekMessage。如果正在讀一個很大的動作;如果從讀檔案,則要花費好幾秒的時間。由於機器反應太遲鈍,會頻繁地點中這個按鈕,以為系統不知道想終止這個操作。如果把File Copy指令放入另外一個執行緒,就不需要在程式碼中放一大堆PeekMessage函式,處理使用者介面的執行緒將與它分開操作,點中Cancel按鈕後會立即得到響應。同樣的道理,在應用中建立一個單獨執行緒來處理所有列印任務也是很有用的,使用者可以在列印處理時繼續使用應用程式。

執行緒的概念

為了瞭解執行緒的概念 ,我們必須先討論一下程式的概念。一個程式通常定義為程式的一個例項。在32位Windows中,程式佔據4GB的虛擬地址空間。與它們在MS-DOS和16位Windows中不同,32位Windows程式是沒有活力的。這就是說,一個32位Windows程式並不什麼指令,它只是佔據著4GB的地址空間,此空間中有應用程式EXE檔案的程式碼和資料。

EXE需要的DLL也將它們的程式碼的資料裝入到程式的地址空間。除了地址空間,程式還佔有某些資源,比如檔案、動態分配和執行緒。當程式終止時,在它生命期中建立的各種資源將被清除。

如上所述,程式是沒有活力的,它只是一個靜態的概念。為了讓程式完成一些工作,程式必須至少佔有一執行緒,所以執行緒是描述程式內的執行,正是執行緒負責執行包含在程式的地址空間中的程式碼。實際上,單個程式可能包含幾個執行緒,它們可以同時執行程式的地址空間中的程式碼。為了做到這一點,每個執行緒有自己的一組CPU暫存器和椎。每個程式至少有一個線址程在執行其地址空間中的程式碼,如果沒有執行緒執行程式地空間中的程式碼,如果沒有執行緒執行程式地址空間中的程式碼,程式也就沒有繼續存在的理由,系統將自動清除程式及其地址空間。為了執行所有這些執行緒,作業系統為每個獨立執行緒安排一些CPU時間,作業系統以輪轉方式向執行緒提供時間片,這就給人一種假象,好象這些執行緒都在同時執行。建立一個32位Windows程式時,它的第一個執行緒稱為主執行緒,由系統自動生成,然後可由這個主執行緒生成額外的執行緒,這些執行緒又可生成更多的執行緒。

執行緒的程式設計技術

1.編寫執行緒函式

所有執行緒必須從一個指定的函式開始執行,該函式稱為執行緒函式,它必須具有下列原型: D WIN YourThreadFunc(LPVOID lpvT.hreadParm);

該函式輸入一個LPVOID型的引數,可以是一個DWORD型的整數,也可以是一個指向一個緩衝區的指標,返回一個DWORD型的值。像WinMain函式一樣,這個函式並不由作業系統呼叫,作業系統呼叫包含在KERNEL32.DLL中的非C執行時的一個內部函式,如StartOfThread,然後由S tartOfThread函式建立起一個異常處理後,呼叫我們的函式。

2.建立一個執行緒

一個程式的主執行緒是由作業系統自動生成,如果要讓一個主執行緒建立額外的執行緒,可以呼叫CreateThread來完成。格式如下:

HANDLE CreateThread(LPSECURITY_ATTRIBUTES jpsa.DWORD cbstack,LPTHREAD_START _ROUTINE lpStartAddr.LPVOID lpvThreadParm,DWORD fdwCreate,LPDWORD lpIDThread);

其中引數意義如下:

lpsa:是一個指向SECURITY_ATTRIBUTES結構的指標。如果想讓為預設屬性的話,可以傳一個NULL;如果想讓任一個子程式都可繼承該執行緒物件控制程式碼,必須指定一個SECURITY _ATTRIBUTES結構,其中bInheritHandle成員初始化為TURE。

cbstark:表示執行緒為自己所用堆疊分配的地址空間大小,0表示採用系統預設值。

lpStartAddr:表示新執行緒開始執行時程式碼所在函式的地址,即為執行緒函式。

lpvThreadParm:是傳入執行緒函式的引數。

fdwCreate:指定控制執行緒建立的附加標誌,可以取兩種值。如果該引數為0,執行緒就會立即開始執行;如果該引數為CREATE_SUSPENDED,則系統產生執行緒後,初始化CPU,登記CONTEXT結構的成員,準備好執行該執行緒函式中的第一條指令,但並不馬上執行,而是掛起該執行緒。

lpIDThrdad:是一個DWORD型別地址,返回賦給該新執行緒的ID值。

3.終止執行緒

如果某執行緒呼叫了ExitThread函式,就可以終止自己,如:

VOID ExtThead(UNIT fuExitCode);

這個函式為呼叫該函式的執行緒設定了退出碼fuExitCode後,就終止該執行緒。

呼叫TenateThread函式亦可終止執行緒。如:

BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode);

該函式用來結束由hThread引數指定的執行緒,並把dwExitCode設成該執行緒的退出碼。

當某個執行緒不再響應時,我們可以用其他執行緒呼叫該函式來終卡這個不響應的執行緒。

4.設定執行緒的相對優先順序

當一個執行緒被首次建立時,它的優先順序等同於它所屬程式的優先順序。在單個程式內可以透過呼叫SetThreadPrionrity函式改變執行緒的相對優先順序。一個執行緒的優先順序是相對於其所屬的程式優先順序而言的。

BOOL SetThreadPriority(HANDLE hThread,intnPriority);

其中引數hThread是指向待修改優先順序執行緒的控制程式碼,nPriority可以是以下的值:


THREAD_PRIORITY_LOWEST

THREAD_PRIORITY_BELOW_NORMAL

THREAD_PRIORITY_NORMAL

THREAD_PRIONRITY_ABOVE_NORMAL

THREAD_PRIONITY_HIGHEST。

5.掛起及恢復執行緒
前文提到過可以建立掛起狀態的執行緒,可以透過傳遞(CREATE_SUSPENDED標誌給函式Cre ated來實現。當這樣操作時,系統建立指定執行緒的核心物件,建立執行緒的棧,在CONTEXT結構中初始化執行緒CPU註冊成員。然而,執行緒物件被分配了一個初始掛起計數值1,這表明系統將不再分配CPU去執行執行緒。要開始執行一個執行緒,另一個執行緒必須呼叫ResumeThread並傳遞給它呼叫CreateThread時返回的執行緒控制程式碼。格式如下:

DWORD ResumeThread(HANDLE hThread);

一個執行緒可以被掛起多次。如果一個執行緒被掛起3次,則該執行緒在它被分配CPU之前必須被恢復3次。除了在建立執行緒時使用CREATE_SUSPENDED標誌,還可以用SuspendThread函式掛起執行緒。格式如下:

DWORD SuspendThread(HANDLE hThread)。

多執行緒程式設計技術的應用

如前所述,為了實現基於下的可視電話,就必須"並行"地執行語音採集、語音編解碼、影像採集、影像編解以及碼流資料的接收與傳送。語音與影像的採集由採集卡進行,我們程式只需初始化該硬體採集卡,然後實時讀取採集資料即可,但語音和影像資料的編解碼以及碼流資料的傳輸都必須由程式去協調執行,讓CPU輪流為各個事件服務,決不能在某一件事件上處理過長。Windows 95下的執行緒正是滿足這種要求的程式設計技術。

本文給出了利用Windows 95環境下用多執行緒程式設計技術實現的基於TCP/IP的可視電話的部分原始碼,其中包括主視窗過程函式以及主叫端與被叫端的TCP/IP接收執行緒函式和語音編解碼的執行緒函式。由於影像編解碼的實時性比語音處理與傳輸模組的實時性的要求要低些,所以以語音編解碼為事件去查影像資料,然後進行影像編解碼,而沒有為影像編解碼去單獨實現一個執行緒。

在主視窗初始化時,用CREATE_SUSPENDED標誌建立了兩個執行緒hThreadG7231和hThreadT CPRev。一個用於語音編解碼,它的執行緒函式為G723Proc,該執行緒不斷查詢本地有無編好碼的語音和影像的碼流,如有,則進行H.223打包,然後透過TCP的埠傳送給對方。另外一個執行緒用於TCP/IP的接收,它的執行緒函式為AcceptThreadProcRiv,該執行緒不斷偵測TCP/IP埠有無對方傳來的碼流,如有,就接收碼流,進行H.223解碼後送入相應的緩衝區。該緩衝區的內容, 由語音編解碼執行緒G723Proc查詢,並送入相應的解碼器,由於使用了多執行緒的程式設計技術,使得作業系統定時去服務語音編解碼模組和傳輸模組,從而保證了通訊的不中斷。 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-959317/,如需轉載,請註明出處,否則將追究法律責任。

相關文章