2011 年 09 月 12 日 by name5566
干净的终止一个线程
之前我们介绍过 ExitThread API(http://name5566.com/185.html),其用于结束当前线程。区别于 ExitThread() 我们还有一个类似的 API — TerminateThread() 可以用于结束其他线程:
// 函数执行成功返回 TRUE,否则返回 FALSE BOOL TerminateThread( // 需要结束的目标线程 HANDLE hThread, // 指定线程的退出码 DWORD dwExitCode );
要注意,TerminateThread 函数建议不使用,因为其会导致被结束线程无法进行清理工作。终止一个线程更好的做法是:对线程设置一个标志,此标志用于表示线程是否需要结束:
DWORD WINAPI ThreadFunc(LPVOID p) { while (true) { // 进行一些工作 // 这里 hRequestExitEvent 是一个 Events 句柄 // 前面谈到过(http://name5566.com/745.html) // 我们可以设置 Wait... 的最长等待时间为 0 用以检查内核对象的状态 // // 其他线程通过设置此 Event 对象为 signaled 状态来结束此线程 // 内核对象为 signaled 状态时,WaitForSingleObject 函数返回 WAIT_OBJECT_0 // 这里不一定要使用 Event 对象,但由于 Event 对象是内核对象 // 因此在一些场合这里可以使用 WaitForMultipleObjects 来同时等待其他内核对象及线程退出请求 if (::WaitForSingleObject(hRequestExitEvent, 0) != WAIT_TIMEOUT) { return (DWORD)-1; } } return 0; }
线程的优先级(Thread Priority)
Win32 有所谓的优先权的概念,较高优先级的线程必然获得较多的 CPU 时间。优先权以一个数值表示,值为 0 ~ 31。
进程的优先级类型(Priority class)决定了进程的重要性,Win32 提供了 4 种优先级类型:
- HIGH_PRIORITY_CLASS — 权值 13
任务管理器就是使用 HIGH_PRIORITY_CLASS,即使系统很忙碌的情况下,它常常会对操作有反应 - IDLE_PRIORITY_CLASS — 权值 4
有时候我们期望程序在 CPU 空闲下来的时候才执行,这个时候使用 IDLE_PRIORITY_CLASS 就很合适 - NORMAL_PRIORITY_CLASS — 权值 7 or 8
一般的应用程序都是使用这个类型 - REALTIME_PRIORITY_CLASS — 权值 24
进程设置为此优先权类型,那么它将优于内核进程和设备驱动进程,不要对 GUI 程序或者典型的服务器程序使用此优先级类型
Windows 的相关 API 为 SetPriorityClass() 和 GetPriorityClass()。
线程的优先级等级(Priority level)决定了同一个进程中的各个线程的相对重要性,实际上线程的优先级等级是对进程的优先级类型的一个修改,Win32 提供了 7 种优先级等级:
- THREAD_PRIORITY_HIGHEST — 权值 +2
- THREAD_PRIORITY_ABOVE_NORMAL — 权值 +1
- THREAD_PRIORITY_NORMAL — 权值 +0
- THREAD_PRIORITY_BELOW_NORMAL — 权值 -1
- THREAD_PRIORITY_LOWEST — 权值 -2
- THREAD_PRIORITY_IDEL — 权值设置为 1
- THREAD_PRIORITY_TIME_CRITICAL — 权值设置为 15
Windows 的相关 API 为 SetThreadPriority() 和 GetThreadPriority()。如果某一个进程的优先级类别为 HIGH_PRIORITY_CLASS,其中一个线程的优先级等级为 THREAD_PRIORITY_LOWEST 那么它的优先级权值就是 13 – 2 = 11。
上面的两个因素决定了线程的优先权,另外还有一个决定线程优先权的因素:动态提升(Dynamic boost)。
首先,我们可以调整系统的设置,使得 CPU 更加倾向于程序还是后台服务。
除了调整系统设置,键盘消息、鼠标消息、计时器消息都可能引发动态提升,例如,线程获得键盘输入时,就获得了一个 +5 的优先级调整值。
最后,当等待状态得到满足时,例如,Wait… 返回时,此线程的优先权就会获得动态提升。
线程的挂起和执行
// 执行指定的线程 // 函数执行成功返回挂起的次数 // 失败返回 0xFFFFFFFF((DWORD)-1) DWORD WINAPI ResumeThread(HANDLE hThread); // 用于挂起指定线程 // 函数执行成功返回先前挂起的次数 // 失败返回 0xFFFFFFFF((DWORD)-1) DWORD WINAPI SuspendThread(HANDLE hThread);
SuspendThread 最常用的一个用途就是使用在编写调试器上。