每一个线程在它的线程内核对象中有一个上下文结构,反映了线程最后一次执行的 CPU 寄存器状态,每隔大约 20ms(可以使用 GetSystemTimeAdjustment 获得,我测得这个间隔大约为 15.6ms),Windows 在所有当前内核对象中查找可调度线程,并选择一个可调度线程,从这个线程的上下文结构中读取 CPU 寄存器状态,这个动作叫做“上下文切换”。这时,这个线程开始执行它的代码,大约 20ms 后,Windows 将 CPU 寄存器的状态保存到这个线程的上下文结构中,这个线程不再执行,Windows 查找下一个可调度线程执行上下文切换,另一个线程继续从它上一次中断的地方开始执行,这个过程从系统开机到系统关闭周而复始。
某些线程不是可调度线程,因为这些线程可能被暂停执行,或者正在待某个任务完成。
由于 WIndows 系统是抢先式操作系统,意味着一个线程可能会在任何时候被其它线程中继,又因为 Windows 系统不是实时操作系统,所以不能保证某一时刻某个线程一定会被调度执行,也不能保证这个线程一定会执行给定的时间片。
线程的暂停和恢复
在线程内核对象内部有一个表示暂停计数器的成员,当你调用 CreateProcess 或 CreateThread 时,这个计数器初始化为 1,避免线程被调度给 CPU,保证线程在完全初始化之前不会执行任何代码,一旦线程完全初始完成,创建函数会检测你是否传递了一个 CREATE_SUSPENDED 标志,如果没有传递这个标志,函数会减少暂停计数器计数,只要计数器为 0,这个线程就成为可调度线程,否则它会暂停执行。
可以使用
1
|
DWORD ResumeThread(HANDLE hThread);
|
来恢复线程的执行,这个函数如果成功,返回之前线程被暂停的次数,否则返回 0xFFFFFFFF。
一个线程可以被暂停多次,那么恢复的话也必须调用 ResumeThread 多次,任何线程都可以调用
1
|
DWORD SuspendThread(HANDLE hThread);
|
来暂停一个线程的执行,只要它有那个线程的句柄,一个线程可以暂停自身的执行,但不可恢复自身。一个线程可以最多被暂停 MAXIMUM_SUSPEND_COUNT (WinNT.h 定义为 127 )次。暂停一个线程时必须非常注意,因为你不知道将要被暂停的线程正在做什么,比如,如果一个线程正在从堆中申请内存,这时,这个线程会在堆中有一个锁,如果这时线程被暂停执行,其它线程会一直待锁被释放,这样会造成死锁。
暂停和恢复一个进程
Windows 并没有提供一个暂停和恢复一个进程内所有线程的函数,我们可以枚举一个进程内的所有线程来达到这个目的,下面是一段摘自 Windows via C/C++ 的一段代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|