线程优先级
Windows 系统有 32 种优先级,分别是 0(最低)到 31(最高)。Windows 是一种抢先式操作系统,意味着高优先级的线程会抢先低优先级的线程的执行,只要有高优先级的线程正在执行,低优先级的线程就不会有机会被调度。
Windows 系统并不直接对线程设置优先级,而是使用进程优先级类和线程相对优先级来设置一个线程的优先级。有多各种方法设置优先级类,可以使用 CreateProcess 创建子进程时传递给 fdwCreate 一个表示优先级类的标识符进行设置,还可以通过
BOOL SetPriorityClass(
HANDLE hProcess,
DWORD fdwPriority);
设置指定进程的优先级类,第三种方式是使用 start 命令行并指定的一个表示优先级选项来启动一个进程,还可以在任务管理器中设置一个进程的优先级。有 6 种进程优先级类,分别是
优先级类 | 标识符 |
实时 | REALTIME_PRIORITY_CLASS |
高 | HIGH_PRIORITY_CLASS |
高于默认 | ABOVE_NORMAL_PRIORITY_CLASS |
默认 | NROMAL_PRIORITY_CLASS |
低于默认 | BELOW_NORMAL_PRIORITY_CLASS |
空闲 | IDLE_PRIORITY_CLASS |
不能在 CreateThread 时设置新线程的相对优先级,只能通过
BOOL SetThreadPriority(
HANDLE hThread,
int nPriority);
设置一个指定线程的优先级,有 7 个相对优先级,分别是
相对优先级 | 常量标识符 |
时间关键 | THREAD_PRIORITY_TIME_CRITICAL |
最高 | THREAD_PRIORITY_HIGHEST |
高于默认 | THREAD_PRIORITY_ABOVE_NORMAL |
默认 | THREAD_PRIORITY_NORMAL |
低于默认 | THREAD_PRIORITY_BELOW_NORMAL |
最低 | THREAD_PRIORITY_LOWEST |
空闲 | THREAD_PRIORITY_IDLE |
线程优先级的动态提升
通常系统在处理一些 I/O 事件或磁盘读取时会动态提升相应线程的优先级,例如,用户按下一个按键,系统会将一个 WM_KEYDOWN 消息放入线程的消息队列中,键盘驱动程序会告诉系统临时提升线程的优先级来处理这个消息,默认情况提升 2 个级别,在第二个时间片,它的优先级降低 1,第三个时间片降到平常水平。系统仅对 1 到 15 之间的优先级做这种提升,这之间的优先级叫做动态优先级范围,系统不会对高于 15 级以上的线程做动态提升,另外,这个提升是由驱动程序告诉系统的。可以使用
BOOL SetProcessPriorityBoost(
HANDLE hProcess,
BOOL bDisablePriorityBoost);
BOOL SetThreadPriorityBoost(
HANDLE hThread,
BOOL bDisablePriorityBoost);
分别设置是否将相应进程或相应线程进行动态提升,使用
BOOL GetProcessPriorityBoost(
HANDLE hProcess,
PBOOL pbDisablePriorityBoost);
BOOL GetThreadPriorityBoost(
HANDLE hThread,
PBOOL pbDisablePriorityBoost);
来获得相应进程或线程是否禁用了动态提升。
另外,如果一个低优先级的线程已准备好执行,可是因为高优先级的线程正在一直执行,这种情况如果持续一段时间,一般是 3 到 4 秒钟,系统会临时将低优先级的线程的优先级提高到 15,并运行两个时间片的时间,然后再将的优先级降到平常水平,这样能保证低优先级的线程能得到执行。
I/O 请求优先级调度
当一个线程正在进行长时间的 I/O 请求时,系统因为慢速的 I/O 操作导致响应不畅,解决这个问题的办法是在开始 I/O 操作之前传递 THREAD_MODE_BACKGROUND_BEGIN 标志给 SetThreadPriority,告诉系统降低当前线程的优先级,在 I/O 完成之后传递 THREAD_MODE_BACKGROUND_END 标志给 SetThreadPriority 将优先级恢复到之前的状态;还可以使用 SetProcessClass 分别传递 PROCESS_MODE_BACKGROUND_BEGIN 和 PROCESS_MODE_BACKGROUND_END 来降低或恢复当前进程中所有线程的优先级,注意,只能对当前进程或线程进行这样的操作,不允许这样改变其它进程和其它线程的优先级。