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;
(5)低于正常:BELOW_ NORMAL _PRIORITY_CLASS;
(6)空闲:IDLE_PRIORITY_CLASS。
我们从Win32任务管理器中可以直观的看到这六个进程类优先级,如下图:
线程的相对优先级包括:
(1)空闲:THREAD_PRIORITY_IDLE;
(2)最低线程:THREAD_PRIORITY_LOWEST;
(3)低于正常线程:THREAD_PRIORITY_BELOW_NORMAL;
(4)正常线程:THREAD_PRIORITY_ NORMAL (缺省);
(5)高于正常线程:THREAD_PRIORITY_ABOVE_NORMAL;
(6)最高线程:THREAD_PRIORITY_HIGHEST;
(7)关键时间: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); }
|