C++中的多執行緒
1.每個程序至少包含一個執行執行緒,稱之為主執行緒,再由主執行緒建立多個子執行緒。c++中沒有內建的多執行緒的支援, 是因為效率、控制以及c++適用的應用程式的範圍,但允許你直接使用作業系統提供的多執行緒支援。由於c++不跨平臺,所以如果有內建的多執行緒支援的話C++就只能使用在支援多執行緒的環境中。
2.為了使用Windows多執行緒函式,需要加入<Windows.h>標頭檔案,用CreateThread來建立一個執行緒。
HANDLE CreateThread(//若建立成功則返回一個控制代碼,失敗則返回NULL,通過呼叫CloseHandle()來結束執行緒,否則它隨著父執行緒結束 LPSECURITY_ATTRIBUTES secAttr,//描述執行緒安全屬性的指標,若為NULL則使用預設的安全描述符 SIZE_T stackSize,//每個執行緒都有自己的堆疊,stackSize就是按位元組指定這個堆疊的大小,若為0則與建立它的執行緒的大小一樣 LPTHREAD_START_ROUTINE ThreadFunc,//執行緒所執行的函式的地址,而這個函式的引數下面的params傳入 LPVOID param, DWORD flags,//確定執行緒的執行狀態,為0則立即執行,為CREATE_SUSPEND則以掛起狀態建立並等待執行,通過ResumeThread()來開始執行 LPDWORD threadId//與執行緒有關的識別符號以threadID所指向的長整型返回 );
BOOL TerminateThread( HANDLE hThread,//將要終止的執行緒的控制代碼 DWORD status//終止狀態 );
VOID ExitThread( DWORD status//終止狀態 );但我們不會使用CreateThread()和ExitThread()來建立並終止執行緒,因為在VC中使用這兩個函式會導致記憶體洩漏。Visual C++用_beginthreadex()和_endthreadex()來取代CreateThread()和Exit Thread()函式。
uintptr_t _beginthreadex( void *setAttr, unsigned stacksize, unsigned ( __clrcall *threadFunc )( void * ), void *param, unsigned flags, unsigned *threadID );
執行緒的掛起和恢復: DWORD SuspendThread(HANDLE hThread); DWORD ResumeThread(HANDLE hThread); 執行緒都有一個掛起計數,計數為0則不會掛起執行緒,為非0則會掛起執行緒。呼叫SuspendThread會增加計數,ResumeThread會減少計數,掛起的執行緒只有計數減為0時才會恢復,所以要恢復一個執行緒,SuspendThread與ResumeThread的呼叫次數應該相等。兩個函式返回的是執行緒先前的掛起計數。
REALTIME_PRIORITY_CLASS HIGH_PRIORITY_CLASS
ABOVE_NORMAL_PRIORITY_CLASS
NORMAL_PRIORITY_CLASS
BELOW_NORMAL_PRIORITY_CLASS
IDLE_PRIORITY_CLASS
在預設情況下,程式的優先順序類別為NORMAL_PRIORITY_CLASS。通常,您不需要改變程式的優先順序類別。事實上,改變程序的優先順序類別對於整個計算機系統的效能會有負面的影響。例如,如果您將一個程式的優先順序類別增加到REALTIME_PRIORITY_CLASS,它就會支配CPU。對於某些特殊的應用程式,可能需要增加應用程式的優先順序類別,但通常並不需要。如前所述,本章的應用程式沒有改變優先順序類別。
當確實需要改變程式的優先順序類別時,可以呼叫SetPriorityClass()。可以呼叫GetPriorityClass()來獲取當前的優先順序類別。這兩個函式的原型如下:
DWORD GetPriorityClass(HANDLE hApp);
BOOL SetPriorityClass(HANDLE hApp, DWORD priority);
在此,hApp是程序的控制代碼。GetPriorityClass()返回應用程式的優先順序類別,如果失敗的話,返回0。對於SetPriorityClass(),priority指定了程序的新優先順序類別。
2.執行緒優先順序: 對於給定的優先順序類別,各個執行緒的優先順序確定了它在程序內接收的CPU時間的多少。當執行緒第一次建立時,它具有普通的優先順序,但是你可以改 變執行緒的優先順序。 可以通過呼叫GetThreadPriority()來獲取執行緒的優先順序設定。可以使用SetThreadPriority()來增加或者減小執行緒的優先順序。 BOOL SetThreadPriority(HANDLE hThread, int priority); int GetThreadPriority(HANDLE hThread); hThread是執行緒的控制代碼。對於SetThreadPriority(),priority是新的優先順序設定。如果發生錯誤,則返回值為0;否則,返回非0值。 GetThreadPriority()會返回當前的優先順序設定。優先順序設定按照從高到低的順序如下:
執行緒優先順序 |
值 |
THREAD_PRIORITY_TIME_CRITICAL |
15 |
THREAD_PRIORITY_HIGHEST |
2 |
THREAD_PRIORITY_ABOVE_NORMAL |
1 |
THREAD_PRIORITY_NORMAL |
0 |
THREAD_PRIORITY_BELOW_NORMAL |
-1 |
THREAD_PRIORITY_LOWEST |
-2 |
THREAD_PRIORITY_IDLE |
-15 |
如果有錯誤發生,則GetThreadPriority()返回THREAD_PRIORITY_ERROR_RETURN。在大多數情況下,如果執行緒具有普通的優先順序類別,
那麼可以隨意地改變它的優先順序設定,而不必擔心會給整個系統的效能帶來災難性的影響。您將會看到,在下面部分開發的執行緒控制面板中,
可以改變程序內執行緒的優先順序設定(但是不能改變優先順序類別)。
獲取主執行緒的控制代碼:
HANDLE GetCurrentThread();
同步:可以使用互斥企業同步執行緒,互斥在給定的時間只允許一個執行緒訪問某個資源。建立互斥訊號量如下:
HANDLE CreateMutex( LPSECURITY_ATTRIBUTES secAttr,//安全指標,為NULL則使用預設的指標 BOOL acquire,//需要互斥體的控制的話則為true,否則為false LPCTSTR lpName//指向一個字串,這個字串是互斥物件的名字,有了名字之後多個就可以用這個名字取控制多個執行緒,若為NULL
則訊號量被限制在一個執行緒內 );當訊號量不需要的時候用CloseHandle()關閉互斥訊號量控制代碼。訊號量可以和下面兩個函式一起使用:
DWORD WaitForSingleObject(//等待一個同步物件,直到這個物件可以使用或者超時之後才會返回 HANDLE hObject,//互斥體的控制代碼 DWORD dwMilliseconds//以毫秒為單位的等待時間,為INFINITE則無限等待 );
函式執行成功則返回WAIT_OBJECT_0,若超時則返回WAIT_TIMEOUT。
BOOL ReleaseMutex(//釋放互斥體並允許其他執行緒獲取它 HANDLE hMutex );二者的使用如下: if(WaitForSingleObject(hMutex,10000)==WAIT_TIMEOUT){//WaitForSingleObject(hMutex,10000)即為進行互斥操作,超時的時候返回WAIT_TIMEOUT,此時丟擲異常返回。 //handle time-out erroe } //access the resource ReleaseMutex(hMutex);