1. 程式人生 > >多執行緒在C、Win32和MFC下的使用方法

多執行緒在C、Win32和MFC下的使用方法

一.前言
    執行緒是執行路徑。一個程序至少要有一個執行緒,也可能包含多個執行緒。若程序關閉了,則在程序中所有的執行緒也自動被銷燬。當我們在一個應用程式中建立一個執行緒時,實際上,它是第二個執行緒。在C或C++中,程式的入口函式是main或wmain(Unicode版本)。在windows的運用程式中,程式的入口點是WinMain或wWinMain。當程式啟動時,作業系統建立第一個執行緒。因此,windows是一個多工作業系統。
二.執行緒函式
    執行緒函式跟普通函式一樣,它帶有一個long void的指標引數。我們可以傳任何型別的資料給這個void型別的指標資料。一個簡單的執行緒函式如下:

ThreadFunction(LPVOID  param)
{
   //do  something
   ……
   ……
   //return  value;
}

三.執行緒屬性
執行緒的優先順序控制程序中執行緒的優先順序。執行緒屬性如下:
● 最高:THREAD_PRIORITY_HIGHEST
● 高於標準:THREAD_PRIORITY_ABOVE_NORMAL
● 標準:THREAD_PRIORITY_NORMAL
● 低於標準:THREAD_PRIORITY_BELOW_NORMAL
● 空閒:THREAD_PRIORITY_IDEL
我們可以用CreateThread函式設定執行緒優先順序。在Win32 API函式中,我們用GetThreadPriority 和 SetThreadPriority獲取和設定執行緒優先順序;或者我們也可以用CWinThread的函式,在程式碼中,我們可以自由的呼叫它。優先順序函式返回一個BOOL型別的變數。
四.各個平臺下的多執行緒
1.C執行時庫的多執行緒 ● _beginthread ● _beginthreadex ● _endthread ● _endthreadex     以上C執行時庫的函式都包含在標頭檔案process.h中。要確保在Microsoft Visual Studio的工程設定是multithreaded DLL。在C執行時庫中,通常是用_beginthread和_beginthreadex函式來建立執行緒。但是,這些執行緒有些不同。_beginthreadex有一些附加的引數,比如安全性和執行緒地址。我們用_beginthread來建立執行緒的話,要用_endthread來結束執行緒。_endthread將自動關閉執行緒的控制代碼。但是,若我們用_endthreadex的話,要用Win32 API的函式CloseHandle來關閉執行緒控制代碼。C執行時庫包含了執行緒本地儲存區(TLS)。我們可以用API或特定的編譯程式碼去使用執行緒本地儲存區。TlsAlloc,TlsFree,TlsGetValue和TlsSetValue通常用來儲存指定的執行緒資料。Microsoft建議,假如你用了C執行時庫的_beginthread函式,你就不要使用像ExitThread或者CreateThread這樣的Win32     API函式。因為,假如你那樣使用的話,可能會導致死鎖。_beginthread在建立執行緒的時候使用多個引數。我們的例子是基於一個簡單控制檯的程式。使用者鍵入執行緒數目建立執行緒,然後我們執行每一個執行緒。
// Secound Thread function
void ThreadProc(void *param);
// First thread
int main()
{
    int n;
    int i;
    int val = 0;
    HANDLE handle;

    printf("\t Thread Demo\n");

    printf("Enter the number of threads : ");
    scanf("%d",&n);

    for(i=1;i<=n;i++)
    {
        val = i;
        handle = (HANDLE) _beginthread( ThreadProc,0,&val); // create thread
        WaitForSingleObject(handle,INFINITE);
    }
    return 0;
}


void ThreadProc(void *param)
{
    int h=*((int*)param);
    printf("%d Thread is Running!\n",h);
    _endthread();
}

主執行緒用Win32 API的函式WaitForSingleObject來等待另一個執行緒的完成。

2.MFC的多執行緒
    CWinThread是所有執行緒操作的基類。MFC支援兩種型別的執行緒:使用者介面執行緒和工作執行緒。使用者介面執行緒是基於windows訊息。工作程序執行在後臺程序中。CWinThread支援工作執行緒和使用者介面執行緒。但是,這裡只討論工作執行緒。
MFC的類層次結構

CObject
  CCmdTarget
    CWinThread
      CWinApp

在以上的類層次結構中,CWinApp應用程式類繼承自CWinThread。因此假如我們建立了一個應用程式類,也同樣建立了執行緒。假如我們建立執行緒的話,它是次執行緒。母類CObject有一些功能像是:支援系列化、執行時間類訊息、支援除錯。派生類CWinThread有同樣的功能。經常用到的一些資料成員和成員函式如下:
資料成員:

● m_hThread – 當前執行緒控制代碼
● m_bAutoDelete – 設定執行緒是否自動釋放
● m_nThreadID – 當前執行緒的ID

函式成員:

● CreateThread – 啟動執行緒的exec執行
● SuspendThread – 掛起執行緒, 增加執行緒掛起數。
● ResumeThread – 恢復執行緒,減少執行緒堆疊數。
● SetThreadPriority – 設定執行緒的優先順序(LOW,BELOW LOW or HIGH)。
● GetThreadPriority – 獲取執行緒的優先順序。

在MFC中,並不是所有的成員函式都是類成員。我們也可以訪問一些全域性函式。這些函式都以Afx開頭。在MFC的執行緒中,AfxBeginThread和AfxEndThread是運用的最廣泛的函式。我們用AfxBeginThread函式建立執行緒。AfxBeginThread語法如下:

CWinThread* AfxBeginThread( AFX_THREADPROC ThreadProc, LPVOID Param,
 int nPriority = THREAD_PRIORITY_NORMAL,UINT  nStackSize = 0,
 DWORD  dwCreateFlags = 0, LPSECURITY_ATTRIBUTES  lpSecurityAttrs = NULL );
ThreadProc是AfxBeginThread函式的第一個引數,我們在這個引數中使用執行緒函式的名稱,在這個引數中傳入void型別的引數指標,此函式的返回值型別是UINT。AfxBeginThread的其它引數是可選的。預設的優先順序是THREAD_PRIORITY_NORMAL。當想要改變其優先順序時,可以呼叫函式SetThreadPriority。我們同樣也可以獲得優先順序。
AfxEndThread用來終止執行緒,AfxEndThread有一個退出程式碼引數列表。
CwinThread *pThread = AfxBeginThread( ThreadFunction, &data);

UINT ThreadFunction(LPVOID param)
{
    DWORD result =0 ;
    // do somthig
    AfxEndThread(exitCode);
    return result;

}

3.Win32的多執行緒
Win32的執行緒使用CreateThread函式來建立,CreateThread函式的語法如下:

HANDLE CreateThread(  LPSECURITY_ATTRIBUTES lpThreadAttributes,
            DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
            LPVOID lpParameter,  DWORD dwCreationFlags, LPDWORD lpThreadId);

當我們想終止執行緒的時候有下面幾種方法:
(1)使用TerminateThread函式
(2)使用ExitThread函式
(3)使用return
但是Advanced Windows建議我們使用Return方法。TerminateThread或ExitThread不能正確的清除執行緒堆疊。函式GetThreadTimes通常用來獲取執行緒的執行時間。函式GetCurrentThreadID是獲取當前執行緒的ID。Sleep指定執行緒休眠,單位為毫秒。比如,Sleep(1000)將使執行緒休眠1000毫秒。函式SwithToThread的功能是切換到其他執行緒。SuspendThread用來掛起一個執行緒。WaitForSingleObject等待一個指定的執行緒,直到執行緒完全完成它的工作。函式WaitForMultipleObject用來等待多個事件。等待的情形:更改通知、控制檯輸入、事件、工作、互斥、程序、訊號量、執行緒和可等待定時器。
五.執行緒的優點
    多執行緒運用程式使用100%的CPU效率。當我們建立一個程序,要需要更多的記憶體空間。多執行緒運用程式跟程序共享一個記憶體空間。每一個執行緒都包含了棧,因此,執行緒比程序佔有的記憶體更少。一個程序可能或可能沒包含多個執行緒,假如你在程序中開啟了多個執行緒,所有的執行緒都共用這個程序的地址空間。