5.設置線程優先級
當一個線程被首次創建時,它的優先級等同于它所屬進程的優先級。在單個進程內可以通過調用SetThreadPriority函數改變線程的相對優先級。一個線程的優先級是相對于其所屬進程的優先級而言的。
BOOL SetThreadPriority(HANDLE hThread, int nPriority); |
其中參數hThread是指向待修改優先級線程的句柄,線程與包含它的進程的優先級關系如下:
線程優先級 = 進程類基本優先級 + 線程相對優先級
進程類的基本優先級包括:
(1)實時:REALTIME_PRIORITY_CLASS;
(2)高:HIGH _PRIORITY_CLASS;
(3)高于正常:ABOVE_NORMAL_PRIORITY_CLASS;
(4)正常:NORMAL _PRIORITY_CLASS;
?。?)低于正常:BELOW_ NORMAL _PRIORITY_CLASS;
(6)空閑:IDLE_PRIORITY_CLASS。
我們從Win32任務管理器中可以直觀的看到這六個進程類優先級,如下圖:
線程的相對優先級包括:
?。?)空閑:THREAD_PRIORITY_IDLE;
?。?)最低線程:THREAD_PRIORITY_LOWEST;
?。?)低于正常線程:THREAD_PRIORITY_BELOW_NORMAL;
?。?)正常線程:THREAD_PRIORITY_ NORMAL (缺省);
?。?)高于正常線程:THREAD_PRIORITY_ABOVE_NORMAL;
(6)最高線程:THREAD_PRIORITY_HIGHEST;
?。?)關鍵時間:THREAD_PRIOTITY_CRITICAL。
下圖給出了進程優先級和線程相對優先級的映射關系:
例如:
HANDLE hCurrentThread = GetCurrentThread(); //獲得該線程句柄 SetThreadPriority(hCurrentThread, THREAD_PRIORITY_LOWEST); |
6.睡眠
VOID Sleep(DWORD dwMilliseconds); |
該函數可使線程暫停自己的運行,直到dwMilliseconds毫秒過去為止。它告訴系統,自身不想在某個時間段內被調度。
7.其它重要API
獲得線程優先級
一個線程被創建時,就會有一個默認的優先級,但是有時要動態地改變一個線程的優先級,有時需獲得一個線程的優先級。
Int GetThreadPriority (HANDLE hThread); |
如果函數執行發生錯誤,會返回THREAD_PRIORITY_ERROR_RETURN標志。如果函數成功地執行,會返回優先級標志。
獲得線程退出碼
BOOL WINAPI GetExitCodeThread( HANDLE hThread, LPDWORD lpExitCode ); |
如果執行成功,GetExitCodeThread返回TRUE,退出碼被lpExitCode指向內存記錄;否則返回FALSE,我們可通過GetLastError()獲知錯誤原因。如果線程尚未結束,lpExitCode帶回來的將是STILL_ALIVE。
獲得/設置線程上下文 BOOL WINAPI GetThreadContext( HANDLE hThread, LPCONTEXT lpContext ); BOOL WINAPI SetThreadContext( HANDLE hThread, CONST CONTEXT *lpContext ); |
由于GetThreadContext和SetThreadContext可以操作CPU內部的寄存器,因此在一些高級技巧的編程中有一定應用。譬如,調試器可利用GetThreadContext掛起被調試線程獲取其上下文,并設置上下文中的標志寄存器中的陷阱標志位,最后通過SetThreadContext使設置生效來進行單步調試。
8.實例
以下程序使用CreateThread創建兩個線程,在這兩個線程中Sleep一段時間,主線程通過GetExitCodeThread來判斷兩個線程是否結束運行:
#define WIN32_LEAN_AND_MEAN #include <stdio.h> #include <stdlib.h> #include <windows.h> #include <conio.h>
DWORD WINAPI ThreadFunc(LPVOID);
int main() { HANDLE hThrd1; HANDLE hThrd2; DWORD exitCode1 = 0; DWORD exitCode2 = 0; DWORD threadId;
hThrd1 = CreateThread(NULL, 0, ThreadFunc, (LPVOID)1, 0, &threadId ); if (hThrd1) printf("Thread 1 launched\n");
hThrd2 = CreateThread(NULL, 0, ThreadFunc, (LPVOID)2, 0, &threadId ); if (hThrd2) printf("Thread 2 launched\n");
// Keep waiting until both calls to GetExitCodeThread succeed AND // neither of them returns STILL_ACTIVE. for (;;) { printf("Press any key to exit..\n"); getch();
GetExitCodeThread(hThrd1, &exitCode1); GetExitCodeThread(hThrd2, &exitCode2); if ( exitCode1 == STILL_ACTIVE ) puts("Thread 1 is still running!"); if ( exitCode2 == STILL_ACTIVE ) puts("Thread 2 is still running!"); if ( exitCode1 != STILL_ACTIVE && exitCode2 != STILL_ACTIVE ) break; }
CloseHandle(hThrd1); CloseHandle(hThrd2);
printf("Thread 1 returned %d\n", exitCode1); printf("Thread 2 returned %d\n", exitCode2);
return EXIT_SUCCESS; }
/* * Take the startup value, do some simple math on it, * and return the calculated value. */ DWORD WINAPI ThreadFunc(LPVOID n) { Sleep((DWORD)n*1000*2); return (DWORD)n * 10; } |
通過下面的程序我們可以看出多線程程序運行順序的難以預料以及WINAPI的CreateThread函數與C運行時庫的_beginthread的差別:
#define WIN32_LEAN_AND_MEAN #include <stdio.h> #include <stdlib.h> #include <windows.h>
DWORD WINAPI ThreadFunc(LPVOID);
int main() { HANDLE hThrd; DWORD threadId; int i;
for (i = 0; i < 5; i++) { hThrd = CreateThread(NULL, 0, ThreadFunc, (LPVOID)i, 0, &threadId); if (hThrd) { printf("Thread launched %d\n", i); CloseHandle(hThrd); } } // Wait for the threads to complete. Sleep(2000);
return EXIT_SUCCESS; }
DWORD WINAPI ThreadFunc(LPVOID n) { int i; for (i = 0; i < 10; i++) printf("%d%d%d%d%d%d%d%d\n", n, n, n, n, n, n, n, n); return 0; } |
運行的輸出具有很大的隨機性,這里摘取了幾次結果的一部分(幾乎每一次都不同):
如果我們使用標準C庫函數而不是多線程版的運行時庫,則程序可能輸出"3333444444"這樣的結果,而使用多線程運行時庫后,則可避免這一問題。
下列程序在主線程中創建一個SecondThread,在SecondThread線程中通過自增對Counter計數到1000000,主線程一直等待其結束:
#include <Win32.h> #include <stdio.h> #include <process.h>
unsigned Counter; unsigned __stdcall SecondThreadFunc(void *pArguments) { printf("In second thread...\n");
while (Counter < 1000000) Counter++;
_endthreadex(0); return 0; }
int main() { HANDLE hThread; unsigned threadID;
printf("Creating second thread...\n");
// Create the second thread. hThread = (HANDLE)_beginthreadex(NULL, 0, &SecondThreadFunc, NULL, 0, &threadID);
// Wait until second thread terminates WaitForSingleObject(hThread, INFINITE); printf("Counter should be 1000000; it is-> %d\n", Counter); // Destroy the thread object. CloseHandle(hThread); }
|
?