Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
1
第 3章 进程、线程和处理机管理向 勇清华大学计算机科学与技术系
2001-08-21
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
2
3.1 进程同步与进程间通信
3.2 线程调度
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
3
3.1 进程同步与进程间通信
3.1.1 Windows 2000/XP的进程互斥和同步
3.1.2 Windows 2000/XP的信号 (signal)
3.1.3 Windows 2000/XP基于文件映射的共享存储区
3.1.4 Windows 2000/XP管道
3.1.5 Windows 2000/XP邮件槽
3.1.6 Windows 2000/XP套接字
3.1.7 剪帖板 (Clipboard)
返回
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
4
3.1.1 Windows 2000/XP的进程互斥和同步返回对象状态可分成可用和不可用两种。 对象可用 (signaled
state)表示该对象不被任何线程使用或所有;而 对象不可用 (nonsignaled state)表示该对象被某线程使用。
对象名称是由用户给出的字符串。不同进程中用同样的名称来创建或打开对象,从而获得该对象在本进程的句柄。
在 Windows 2000/XP中提供了 互斥 对象,信号量 对象和事件 对象等三种同步对象和相应的系统调用,用于进程和线程同步。从本质上讲,这组同步对象的功能是相同的,它们的区别在于 适用场合和效率会有所不同 。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
5
3.1.1.1 互锁变量访问
3.1.1.2 临界区对象 (Critical Section)
3.1.1.3 互斥对象 (Mutex)
3.1.1.4 信号量对象 (Semaphore)
3.1.1.5 事件对象 (Event)
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
6
互锁变量访问是 最基本的互斥手段,其他的互斥和共享机制都是以它为基础的。它相当于硬件 TS指令。用于对整型变量的操作,可避免线程间切换对操作连续性的影响。这组互锁变量访问 API包括:
InterlockedExchange进行 32位数据的先读后写原子操作;
InterlockedExchangePointer对指针的 Exchange原子操作;
InterlockedCompareExchange依据比较结果进行赋值的原子操作;
InterlockedCompareExchangePointer对指针的 CompareExchange原子操作;
InterlockedExchangeAdd先加后存结果的原子操作;
InterlockedDecrement先减 1后存结果的原子操作;
InterlockedIncrement先加 1后存结果的原子操作。
3.1.1.1 互锁变量访问返回下面是 InterlockedExchange()的汇编结果:
17,InterlockedExchange(&lCounter,lTemp);
0040109A mov esi,esp
0040109C mov eax,dword ptr [ebp-8]
0040109F push eax ; lTemp压栈
004010A0 push offset lCounter (004299ec) ; lCounter地址压栈
004010A5 call dword ptr [__imp__InterlockedExchange@8 (0042c178)]
004010AB cmp esi,esp
004010AD call __chkesp (00403940) ; 这个函数就一条指令
77E66AC3 mov ecx,dword ptr [esp+4] ; 取 lCounter的地址
77E66AC7 mov edx,dword ptr [esp+8] ; 取 lTemp
77E66ACB mov eax,dword ptr [ecx] ; 取 lCounter
77E66ACD nop
77E66ACE cmpxchg dword ptr [ecx],edx ; 比较交换指令
77E66AD1 jne 77E66ACD
77E66AD3 ret 8
实例,2001-08-12 InterlockedIncrement.cpp
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
8
3.1.1.2 临界区对象 (Critical Section)
只能用于在同一进程内使用的临界区,同一进程内各线程对它的访问是互斥进行的。相关
API包括:
– InitializeCriticalSection对临界区对象进行初始化;
– EnterCriticalSection等待占用临界区的使用权,得到使用权时返回;
– TryEnterCriticalSection非等待方式申请临界区的使用权;申请失败时,返回 0;
– LeaveCriticalSection释放临界区的使用权;
– DeleteCriticalSection释放与临界区对象相关的所有系统资源。
返回实例,2001-08-12 CriticalSection.cpp
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
9
3.1.1.3 互斥对象 (Mutex)
互斥对象相当于互斥信号量,在一个时刻只能被一个线程使用。有关的 API:
– CreateMutex创建一个互斥对象,返回对象句柄;
– OpenMutex返回一个已存在的互斥对象的句柄,用于后续访问;
– ReleaseMutex释放对互斥对象的占用,使之成为可用;
返回实例,2001-08-14 Mutex.cpp
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
10
3.1.1.4 信号量对象 (Semaphore)
信号量对象的取值在 0到指定最大值之间,
用于限制并发访问的线程数。有关的 API:
– CreateSemaphore创建一个信号量对象,指定最大值和初值,返回对象句柄;
– OpenSemaphore返回一个已存在的信号量对象的句柄,用于后续访问;
– ReleaseSemaphore释放对信号量对象的占用;
返回实例,2001-08-14 Semaphore.cpp
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
11
3.1.1.5 事件对象 (Event)
事件对象相当于 "触发器 ",可通知一个或多个线程某事件的出现。有关的 API:
– CreateEvent创建一个事件对象,返回对象句柄;
– OpenEvent返回一个已存在的事件对象的句柄,用于后续访问;
– SetEvent和 PulseEvent设臵指定事件对象为可用状态;
– ResetEvent设臵指定事件对象为不可用状态;手工复位,并唤醒所有等待线程;
返回实例,2001-08-14 Event.cpp
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
12
3.1.1.6 同步对象等待对于这些同步对象,Windows 2000/XP提供了两个 统一的等待操作 WaitForSingleObject和
WaitForMultipleObjects。
(1) WaitForSingleObject在 指定的时间内 等待指定对象为可用状态 (signaled state);
DWORD WaitForSingleObject( HANDLE hHandle,
// handle of object to wait for
DWORD dwMilliseconds
// time-out interval in milliseconds
);
返回
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
13
(2) WaitForMultipleObjects在指定的时间内等待多个对象为可用状态;
DWORD WaitForMultipleObjects( DWORD nCount,
//对象句柄数组中的句柄数;
CONST HANDLE *lpHandles,
// 指向对象句柄数组的指针,数组中可包括多种对象句柄;
BOOL bWaitAll,
// 等待标志,TRUE表示所有对象同时可用,FALSE表示至少一个对象可用;
DWORD dwMilliseconds // 等待超时时限;
);
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
14
3.1.2 Windows 2000/XP的信号 (signal)
3.1.2.1 SetConsoleCtrlHandler和
GenerateConsoleCtrlEvent
3.1.2.2 signal和 raise
返回信号是进程与外界的一种低级通信方式。进程可发送信号,每个进程都有指定信号处理例程。信号通信是单向和异步的。 Windows 2000/XP有 两组 与信号相关的系统调用,分别处理不同的信号。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
15
3.1.2.1 SetConsoleCtrlHandler和
GenerateConsoleCtrlEvent
返回
SetConsoleCtrlHandler在本进程的处理例程
(HandlerRoutine)列表中 定义或取销用户定义的处理例程 ;如:缺省时,它有一个 CTRL+C
输入的处理例程,我们可利用本调用来忽视或恢复 CTRL+C输入的处理;
GenerateConsoleCtrlEvent发送信号 到与本进程共享同一控制台的 控制台进程组 ;
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
16
处理信号列表 (5种 )
C T R L _ C _ E V E N T 收到 C T R L + C 信号
C T R L _ B R E A K _ E V E N T 收到 C T R L + B R E A K 信号
C T R L _ C L O S E _ E V E N T 当用户关闭控制台时系统向该控制台的所有进程发送的控制台关闭信号
C T R L _ L O G O F F _ E V E N T 用户退出系统时系统向所有控制台进程发送的退出信号
C T R L _ S H U T D O W N _ E V E N T 系统关闭时向所有控制台进程发送的关机信号实例,2001-08-15 SetConsoleCtrlHandler.cpp
该程序可改信号处理例程。主程序会发送一个 Ctrl-C信号。对 Ctrl-C信号的处理是一个响声,对关窗口信号的处理是显示一段提示。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
17
3.1.2.2 signal和 raise
返回
signal设臵中断信号处理例程;如,SIGINT
( CTRL+C),SIGABRT异常中止等信号的处理;
raise给本进程发送一个信号;
– UNIX中的 kill可向其他进程发信号,但在 Windows
2000/XP中没有 kill。
处理信号列表( 6种)
S I G A B R T 非正常终止
S I G F P E 浮点计算错误
S I G I L L 非法指令
S I G I N T C T R L + C 信号 ( 对 W i n 3 2 无效 )
S I G S E G V 非法存储访问
S I G T E R M 终止请求实例,2001-08-14 raise.cpp
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
18
3.1.3 Windows 2000/XP基于文件映射的共享存储区返回
将整个文件映射为进程虚拟地址空间的一部分 来加以访问。在 CreateFileMapping和 OpenFileMapping时可以指定对象名称。
– CreateFileMapping为指定文件 创建一个文件映射对象,返回对象指针;
– OpenFileMapping打开一个命名的文件映射对象,返回对象指针;
– MapViewOfFile把文件映射到本进程的地址空间,返回映射地址空间的首地址;
这时可利用首地址进行读写;
– FlushViewOfFile可把映射地址空间的 内容写到物理文件 中;
– UnmapViewOfFile拆除文件映射与本进程地址空间间映射关系 ;
随后,可利用 CloseHandle关闭文件映射对象;
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
19
共享存储区实例
http://www.microsoft.com/msj/defaultframe.asp?page=/msj/1198/
wicked/wicked1198.htm&nav=/msj/1198/newnav.htm
在 CsharedMemory::Create中:
– SharedMem.cpp,Line 71,CreateFileMapping,创建文件映射对象;
– SharedMem.cpp,Line 92,MapViewOfFile,映射文件;
在 CsharedMemory::Delete中:
– SharedMem.cpp,Line 166,UnmapViewOfFile,拆除文件映射;
– SharedMem.cpp,Line 168,CloseHandle,关闭文件映射对象;
在 CsharedMemory::Write和 CsharedMemory::Read中:
– SharedMem.cpp,Line 206和 226,CopyMemory进行数据传送;
2001-08-16 Nov98Wicked-FileMapping.exe
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
20
3.1.4 Windows 2000/XP管道
Windows 2000/XP提供无名管道和命名管道两种管道机制。
Windows 2000/XP的无名管道类似于
UNIX系统的管道,但提供的安全机制比
UNIX管道完善。
– 利用 CreatePipe可创建无名管道,并得到两个读写句柄;
– 然后利用 ReadFile和 WriteFile可进行无名管道的读写。
返回
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
21
命名管道,一个服务器端与一个客户进程间的通信通道;可用于不同机器上进程通信;
– 类型分为:字节流,消息流(报文);
– 访问分为:单向读,单向写,双向;
– 通常采用 client-server模式,连接本机或网络中的两个进程
– 管道名字:
作为客户方(连接到一个命名管道实例的一方)时,
可以是 "\\serverName\pipe\pipename";
作为服务器方 (创建命名管道的一方 )时,只能取
serverName为 \\.\pipe\PipeName,不能在其它机器上创建管道;
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
22
命名管道服务器支持多客户,为每个管道实例建立单独线程或进程。
– CreateNamedPipe在服务器端创建并返回一个命名管道句柄;
– ConnectNamedPipe在服务器端等待客户进程的请求;
– CallNamedPipe从管道客户进程建立与服务器的管道连接;
– ReadFile,WriteFile(用于阻塞方式)、
ReadFileEx,WriteFileEx(用于非阻塞方式)用于命名管道的读写;
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
23
命名管道实例
MSDN,NamePipe,Named Pipe Sample中有一个例子,
通过命名管道进行多个进程间的通信。其中的主要内容有:
Server32.c中 ServerProc函数是服务器进程中的主要过程。它创建命名管道( CreateNamedPipe),并等待客户连接( ConnectNamedPipe)。它为每一个用户连接建立一个线程( Line 345,CreateThread)。服务器进程会每个客户送来的数据( Line 362,ReadFile),
并发给每个客户( Line 454,WriteFile)。
实例,2001-08-16 IPC-Namepipe.cpp
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
24
3.1.5 Windows 2000/XP邮件槽返回
邮件槽 (mailslot):驻留在 OS核心,不定长数据块(报文),不可靠传递
通常采用 client-server模式,单向 的,从 client发往
server; server负责创建邮件槽,它可从邮件槽中读消息; client可利用邮件槽的名字向它发送消息;
邮件槽名字:
– 作为 client(发送方)打开邮件槽时,可以是
"\\range\mailslot\[path]name",这里 range可以是,(local
computer),computerName,domainName,*(primary domain);
– 作为 server(接收方)只能在本机建立邮件槽,名字可为
"\\.\mailslot\[path]name";
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
25
有关的 API如:
– CreateMailslot服务器方创建邮件槽,返回其句柄;
– GetMailslotInfo服务器查询邮件槽的信息,如:消息长度、消息数目、读操作等待时限等;
– SetMailslotInfo服务器设臵读操作等待时限;
– ReadFile服务器读邮件槽;
– CreateFile客户方打开邮件槽;
– WriteFile客户方发送消息;
在邮件槽的所有服务器句柄关闭后,邮件槽被关闭。这时,未读出的报文被丢弃,所有客户句柄都被关闭。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
26
3.1.6 Windows 2000/XP套接字返回
双向 的,数据格式为字节流(一对一)或报文(多对一,
一对多);主要用于网络通信;
支持 client-server模式和 peer-to-peer模式,本机或网络中的两个或多个进程进行交互。提供 TCP/IP协议支持
UNIX套接字 (基于 TCP/IP),send,sendto,recv,
recvfrom;
在 Windows 2000/XP中的规范称为 "Winsock"(与协议独立,或支持多种协议 ),WSASend,WSASendto,
WSARecv,WSARecvfrom;
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
27
3.1.7 剪帖板 (Clipboard)
当进程间的 复杂信息交流 需要约定交流信息的格式。剪帖板就是 Windows 2000/XP提供的一种信息交流方式,可增强进程的信息交流能力。
Windows 2000/XP提供了一组相关的 API来完成应用进程与剪帖板间的格式化信息交流。
当执行复制操作时,应用程序将选中的数据以标准的格式或者应用程序定义的格式 放到剪贴板 中,然后其他的应用程序可以从剪贴板中以其可以支持的格式 获取所需要的数据 。
返回
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
28
剪帖板信息格式
剪帖板中提供了许多标准的剪帖板信息格式。如:文本格式和位图格式。
允许用户进程注册新的剪帖板信息格式。
F o r m a t T y p e D e s c r i p t i o n
T ex t F o r m a t s
C F _ O E M T E XT T ex t c o n t a i n i n g ch a r ac t e r s f r o m t h e O E M c h ar ac t er s et
C F _ T E XT T ex t c o n t a i n i n g ch a r ac t e r s f r o m t h e A NS I ch a r ac t e r s et
C F _ UN I C O DE T E XT T ex t c o n t a i n i n g U n i c o d e ch a r ac t e r s
B i t m ap f o r m a t s
C F _ B I T M A P Dev i c e- d ep e n d en t b i t m a p ( H B I T M AP )
C F _ DI B Dev i c e i n d e p en d en t b i t m ap ( H B I T M A P I NF O )
C F _ T I F F T ag g ed I m ag e F i l e F o r m a t
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
29
与剪帖板相关的 API
– OpenClipboard,打开剪帖板;
– CloseClipboard:关闭剪帖板;
– EmptyClipboard:清空剪帖板;
– SetClipboardData:把数据及其格式加入剪帖板;
– GetClipboardData:从剪帖板读取数据;
– RegisterClipboardFormat:注册剪帖板格式;
实例
– 这个例子可把命令行参数复制到剪帖板中。程序中的主要内容是函数 Cclipboard_SetText中。
– 2001-08-16 clipboard.cpp
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
30
3.2 Windows 2000/XP的线程调度
Windows 2000/XP的处理机调度的 调度对象 是线程。
Windows 2000/XP的线程调度并不是单纯使用某一种调度算法,而是 多种算法的综合体,针对实际系统的需要进行针对性的优化和改进。
返回
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
31
3.2.1 Windows 2000/XP线程状态
3.2.2 Windows 2000/XP的线程调度特征
3.2.3 Win32中与线程调度相关的应用编程接口
3.2.4 线程优先级
3.2.5 线程时间配额
3.2.6 调度数据结构
3.2.7 调度策略
3.2.8 线程优先级提升
3.2.9 对称多处理机系统上的线程调度
3.2.10 空闲线程
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
32
3.2.1 Windows 2000/XP线程状态返回
Windows 2000/XP的线程是 内核线程,系统的处理机调度对象为线程。 Windows 2000/XP把线程状态分成下面 七种状态,与单挂起进程模型很相似,它们的主要区别在于从就绪状态到运行状态的转换中间多上一个 备用状态,以优化线程的抢先特征。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
33
运行 终止就绪等待描述表切换抢先或时间片结束等待对象句柄执行完成初始化转换备用选择执行 抢先放入就绪队列等待完成等待完成换出的内核堆栈换入的内核堆栈重新初始化创建和初始化线程对象
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
34
就绪状态 (Ready),线程已获得除处理机外的所需资源,正等待调度执行。
备用状态 (Standby),已选择好线程的执行处理机,正等待描述表切换,以进入运行状态。系统中每个处理机上只能有一个处于备用状态的线程。
运行状态 (Running),已完成描述表切换,线程进入运行状态。线程会一直处于运行状态,直到被抢先、时间片用完、
线程终止或进入等待状态。
等待状态 (Waiting),线程正等待某对象,以同步线程的执行。当等待事件出现时,等待结束,并根据优先级进入运行或就绪状态。
转换状态 (Transition),转换状态 与就绪状态类似,但线程的内核堆栈位于外存。当线程等待事件出现而它的内核堆栈处于外存时,线程进入转换状态;当线程内核堆栈被调回内存时,线程进入就绪状态。
终止状态 (Terminated),线程执行完就进入终止状态;如执行体有一指向线程对象的指针,可将处于终止状态的线程对象重新初始化,并再次使用。
初始化状态 (Initialized),线程创建过程中的线程状态;
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
35
Windows 2000/XP的线程控制
CreateThread完成线程创建,在调用进程的地址空间上创建一个线程,以执行指定的函数;
它的返回值为所创建线程的句柄。
ExitThread用于结束当前线程。
SuspendThread可挂起指定的线程。
ResumeThread可激活指定线程,它的对应操作是递减指定线程的挂起计数,当挂起计数减为 0时,线程恢复执行。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
36
3.2.2 Windows 2000/XP的线程调度特征返回调度单位 是线程而不是进程,采用 严格的抢先式动态优先级 调度,依据 优先级 和分配 时间配额 来调度。
每个优先级的 就绪线程 排成一个 先进先出 队列;
当一个线程状态 变成就绪 时,它可能立即运行或排到相应优先级队列的 尾部 。
总运行 优先级最高的就绪线程 ;
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
37
完全的 事件驱动 机制,在被抢先前没有保证的运行时间;没有形式的调度循环;
– 进入就绪 事件;
– 时间配额用完 事件;
– 优先级改变 事件;
– 亲合处理机集合改变 事件;
在同一优先级的各线程按 时间片轮转 算法进行调度;
在多处理机系统中多个线程 并行 运行;
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
38
3.2.3 Win32中与线程调度相关的 API
Suspend/ResumeThread
Get/SetPriorityClass
Get/SetThreadPriority
Get/SetProcessPriorityBoost
Get/SetThreadPriorityBoost
Get/SetProcessAffinityMask
SetThreadAffinityMask
SetThreadIdealProcessor
SwitchToThread
Sleep
SleepEx 返回
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
39
3.2.4 线程优先级返回
16 个 实时 线程优先级
15 个 可变 线程 优先级
1 个 系统 线 程 优先级
( 零页线程)
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
40
实时 优先级范围16 -31
实时 优先级的相对实时可变 优先级范围1 -15
可变 优先级的相对 实时实时 优先级的相对 空闲可变 优先级的相对 空闲实时空闲中下中级中上高级仅用于零页线程(Wi n32 应用不能使用)
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
41
1,实时优先级
在应用程序中,要把线程的优先级提升到实时优先级,用户必须有升高线程优先级的权限。
如果用户进程在实时优先级运行时间过多,它将可能阻塞关键系统功能的执行,阻塞系统线程的运行;但不会阻塞硬件中断处理。
在被其他线程抢先时,具有实时优先级线程与具有可变优先级线程的行为是不同的。
Windows 2000/XP并不是通常意义上的实时,
并不提供实时操作系统服务。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
42
线程 优先级0 -31
2,中断优先级与线程优先级的关系
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
43
3.2.5 线程时间配额
时间配额是一个线程从进入运行状态到
Windows 2000/XP检查是否有其他优先级相同的线程需要开始运行之间的 时间总和 。
一个线程用完了自己的时间配额时,如果没有其它相同优先级线程,Windows 2000/XP
将重新给该线程 分配一个新的时间配额,并继续运行。
时间配额不是一个时间长度值,而一个称为配额单位 (quantum unit)的整数。
返回
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
44
1,时间配额的计算
缺省时,在 Windows 2000专业版中线程时间配额为 6;
而在 Windows 2000服务器中线程时间配额为 36。
– 在 Windows 2000服务器中取较长缺省时间配额的原因是,保证客户请求所唤醒的服务器应用有足够的时间在它的时间配额用完前完成客户的请求并回到等待状态。
每次 时钟中断,时钟中断服务例程从线程的时间配额中减少一个固定值 (3)。
– 如果没有剩余的时间配额,系统将 触发时间配额用完处理,选择另外一个线程进入运行状态。
– 在 Windows 2000专业版中,由于每个时钟中断时减少的时间配额为 3,一个线程的缺省运行时间为 2个时钟中断间隔 ;在
Windows 2000服务器中,一个线程的缺省运行时间为 12个时钟中断间隔 。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
45
如果时钟中断出现时系统正在处在 DPC/线程调度层次以上 (如系统正在执行一个延迟过程调用或一个中断服务例程 ),当前线程的 时间配额仍然要减少 。甚至在整个时钟中断间隔期间,当前线程一条指令也没有执行,它的时间配额在时钟中断中也会被减少。
不同硬件平台的时钟中断间隔是不同的,时钟中断的频率是由硬件抽象层确定的,而不是内核确定的。
– 例如,大多数 x86单处理机系统的时钟中断间隔为 10
毫秒,大多数 x86多处理机系统的时钟中断间隔为 15
毫秒。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
46
在等待完成时允许减少部分时间配额 。
– 当优先级小于 14的线程执行一个等待函数 (如
WaitForSingleObject或 WaitForMultipleObjects)时,
它的时间配额被减少 1个时间配额单位。当优先级大于等于 14的线程在执行完等待函数后,它的时间配额被重臵。
这种部分减少时间配额的做法可解决 线程在时钟中断触发前进入等待状态 所产生的问题。
– 如果不进行这种部分减少时间配额操作,一个线程可能永远不减少它的时间配额。例如,一个线程运行一段时间后进入等待状态,再运行一段时间后又进入等待状态,但在时钟中断出现时它都不是当前线程,则它的时间配额永远也不会因为运行而减少。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
47
2,时间配额的控制在系统注册库中的一个注册项
,HKLM\SYSTEM\CurrentControlSet\Control\Pr
iorityControl\Win32PrioritySeparation”,允许用户指定线程时间配额的相对长度 (长或短 )和前台进程的进程的时间配额是否加长。该注册项为 6位,分成 3个字段,每个字段占 2位。
前台进程时间配额提升时间配额长度 前后台变化
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
48
时间配额长度字段 (Short vs,Long):
– 1表示长时间配额,2表示短时间配额。 0或 3表示缺省设臵
(Windows 2000专业版的缺省设臵为短时间配额,Windows
2000服务器版的缺省设臵为长时间配额 )。
前后台变化字段 (Variable vs,Fixed):
– 1表示改变前台进程时间配额,2表示前后台进程的时间配额相同。 0或 3表示缺省设臵 (Windows 2000专业版的缺省设臵为改变前台进程时间配额,Windows 2000服务器版的缺省设臵为前后台进程的时间配额相同 )。
前台进程时间配额字段 (Foreground Quantum Boost):
– 该字段的取值只能是 0,1或 2(取 3是非法的,被视为 2)。该字段是一个时间配额表索引,用于设臵前后台进程的时间配额,后台进程的时间配额为第一项,前台进程的时间配额依据该字段从时间配额表中得到。该字段的值保存在内核变量
PsPrioritySeparation。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
49
时间配额的设置短时间配额 长时间配额改变前台进程时间配额 6 12 18 12 24 36
前后台进程的时间配额相同 18 18 18 36 36 36
如果当前窗口切换到一个优先级高于空闲优先级类的进程中某线程,Win32子系统将用注册项
Win32PrioritySeparation的前台进程时间配额字段作为索引,依据一个有 3个元素的数组
PspForegroundQuantum中取值,来设臵该进程中所有线程的时间配额。该数组的内容由注册项 Win32PrioritySeparation的另外 2个字段确定。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
50
提高前台线程优先级的问题
假设用户首先启动了一个运行时间很长的电子表格计算程序,然后切换到一个计算密集型的应用 (如一个需要复杂图形显示的游戏 )。
如果前台的游戏进程提高它的优先级,后台的电子表格将会几乎得不到 CPU时间。
但增加游戏进程的时间配额,则不会停止电子表格计算的执行,只是给游戏进程的 CPU时间多一些。
如果用户希望运行一个交互式应用程序时的优先级比其他交互进程的优先级高,可利用任务管理器来修改进程的优先级类型为中上或高级,也可利用命令行在启动应用时使用命令,start /abovenormal”或,start
/high”来设臵进程优先级类型。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
51
3.2.6 调度数据结构返回进程 进程线程 线程线程 线程
31
0
就绪位图
31 0
空闲位图
31 0
缺省基本优先级缺省处理机偏好缺省时间配额基本优先级当前优先级处理机偏好时间配额线程调度器就绪队列
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
52
就绪位图 (KiReadySummary)
– 为了提高调度速度,Windows 2000维护了一个称为就绪位图 (KiReadySummary)的 32位量。就绪位图中的每一位指示一个调度优先级的 就绪队列 中是否有线程等待运行。 B0与调度优先级 0相对应,B1与调度优先级 1相对应,等待。
空闲位图 (KiIdleSummary)
– Windows 2000还维护一个称为空闲位图
(KiIdleSummary)的 32位量。空闲位图中的每一位指示一个 处理机是否处于空闲状态 。
调度器自旋锁 (KiDispatcherLock)
– 为了防止调度器代码与线程在访问调度器数据结构时发生冲突,处理机调度仅出现在 DPC/调度层次。
但在多处理机系统中,修改调度器数据结构需要额外的步骤来得到内核调度器自旋锁
(KiDispatcherLock),以协调各处理机对调度器数据结构的访问。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
53
变量名 变量类型 功能说明
K iD ispa tc he r L oc k 自旋锁 调度器自旋锁
K e N umbe r Pro c e sso r s 字节 系统中的可用处理机数目
K e A c tive Pro c e sso r s 32 位位图 描述系统中各处理机是否正处于运行状态
K iI dle Summa r y 32 位位图 描述系统中各处理机是否处于空闲状态
K iRe a dy Summa r y 32 位位图 描述各调度优先级是否有就绪线程等待调度
K iD ispa tc he r Re a dy L istH e a d 有 32 个元素的数组
32 个元素分别指向 32 个就绪队列与线程调度相关的内核变量
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
54
3.2.7 调度策略返回
Windows 2000/XP严格基于线程的优先级来确定哪一个线程将占用处理机并进入运行状态。
Windows 2000/XP在单处理机系统和多处理机系统中的线程调度是不同的。我们首先介绍单处理机系统中线程调度。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
55
1,主动切换线程优先级运行状态 就绪状态转到阻塞状态
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
56
许多 Win32等待函数调用 (如
WaitForSingleObject或 WaitForMultipleObjects
等 )都使线程等待某个对象,等待的对象可能有事件、互斥信号量、资源信号量,I/O操作、进程、线程、窗口消息等。
通常进入等待状态线程的时间配额不会被重臵,
而是在等待事件出现时,线程的时间配额被减 1,
相当于 1/3个时钟间隔;如果线程的优先级大于等于 14,在等待事件出现时,线程的时间配额被重臵。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
57
2,抢先线程优先级运行状态 就绪状态从 阻塞状态 唤醒当一个高优先级线程进入就绪状态时,正在处于运行状态的低优先级线程被抢先。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
58
可能在以下两种情况下出现抢先:
– 高优先级线程的等待完成,即一个线程等待的事件出现。
– 一个线程的优先级被增加或减少。
用户态下运行的线程可以抢先内核态下运行的线程。
– 在判断一个线程是否被抢先时,并不考虑线程处于用户态还是内核态,调度器只是依据线程优先级进行判断。
当线程被抢先时,它被放回相应优先级的就绪队列的队首。
– 处于实时优先级的线程在被抢先时,时间配额被重臵为一个完整的时间配额;
– 处于动态优先级的线程在被抢先时,时间配额不变,
重新得到处理机使用权后将运行到剩余的时间配额用完。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
59
3,时间配额用完线程优先级运行状态 就绪状态线程完整用完一个规定的时间片值时,重新赋予新时间片值,优先级降一级(不低于基本优先级),放在相应优先级就绪队列的尾部;
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
60
如果刚用完时间配额的线程 优先级降低 了,
Windows 2000将寻找一个优先级高于刚用完时间配额线程的新设臵值的就绪线程。
如果刚用完时间配额的线程的 优先级没有降低,
并且 有其他优先级相同的就绪线程,Windows
2000将选择相同优先级的就绪队列中的下一个线程进入运行状态,刚用完时间配额的线程被排到就绪队列的队尾 (即分配一个新的时间配额并把线程状态从运行状态改为就绪状态 )。
如果 没有优先级相同的就绪线程 可运行,刚用完时间配额的线程将得到一个新的时间配额并继续运行。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
61
4,线程结束
当线程完成运行时,它的状态从运行状态转到终止状态。
线程完成运行的原因可能是
– 通过调用 ExitThread而从主函数中返回
– 通过被其他线程通过调用 TerminateThread来终止。
如果处于终止状态的线程对象上没有未关闭的句柄,则该线程将被从进程的线程列表中删除,
相关数据结构将被释放。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
62
时间运行基本优先级线程优先级等待 运行 运行等待结束时的优先级提升时间配额基本 优先级的时 间片轮转时间配额用完 时的优先级降低被抢先
( 时间配额用完前)3.2.8 线程优先级提升返回线程由于调用等待函数而阻塞时,减少一个时间片,并依据等待事件类型提高优先级;如等待键盘事件比等待磁盘事件的提高幅度大。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
63
在下列 5种情况下,Windows 2000会提升线程的当前优先级:
– I/O操作完成
– 信号量或事件等待结束
– 前台进程中的线程完成一个等待操作
– 由于窗口活动而唤醒图形用户接口线程
– 线程处于就绪状态超过一定时间,但没能进入运行状态 (处理机饥饿 )
线程优先级提升的目的是改进系统吞吐量、响应时间等整体特征,解决线程调度策略中潜在的不公正性。但它也不是完美的,它并不会使所有应用都受益。
Windows 2000永远不会提升实时优先级范围内
(16至 31)的线程优先级。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
64
1,I/O操作完成后的线程优先级提升
在完成 I/O操作后,Windows 2000将临时提升等待该操作线程的优先级,以 保证等待 I/O操作的线程能有更多的机会立即开始处理得到的结果 。
为了避免 I/O操作导致对某些线程的不公平偏好,在 I/O
操作完成后唤醒等待线程时将把该线程的时间配额减 1。
线程优先级的实际 提升值是由设备驱动程序决定 的。与
I/O操作相关的线程优先级提升建议值在文件,Wdm.h”
或,Ntddk.h”中。设备驱动程序在完成 I/O请求时通过内核函数 IoCompleteRequest来指定优先级提升的幅度。
线程优先级的提升幅度与 I/O请求的响应时间要求是一致的,响应时间要求越高,优先级提升幅度越大 。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
65
线程优先级提升的建议值设备 优先级提升值磁盘、光驱、并口、视频 1
网络、邮件槽、命名管道、串口 2
键盘、鼠标 6
音频 8
线程优先级提升是以线程的基本优先级为基点的,不是以线程的当前优先级为基点。
当用完它的一个时间配额后,线程会降低一个优先级,
并运行另一个时间配额。这个降低过程会一直进行下去,
直到线程的优先级降低至原来的基本优先级。
优先级提升策略仅适用于可变优先级范围 (0到 15)内的线程。不管线程的优先级提升幅度有多大,提升后的优先级都不会超过 15而进入实时优先级。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
66
2,等待事件和信号量后的线程优先级提升
当一个等待执行事件对象或信号量对象的线程完成等待后,它的优先级将 提升一个优先级 。
阻塞于事件或信号量的线程得到的处理机时间比处理机繁忙型线程要少,这种提升可减少这种不平衡带来的影响。
SetEvent,PulseEvent或 ReleaseSemaphore函数调用可导致事件对象或信号量对象等待的结束。
提升是以线程的基本优先级为基点的,而不是线程的当前优先级。提升后的优先级永远不会超过 15。在等待结束时,线程的时间配额被减 1,并在提升后的优先级上执行完剩余的时间配额;随后降低 1个优先级,运行一个新的时间配额,直到优先级降低到初始的基本优先级。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
67
3,前台线程在等待结束后的优先级提升
对于前台进程中的线程,一个内核对象上的等待操作完成时,内核函数 KiUnwaitThread会 提升线程的当前优先级 (不是线程的基本优先级 ),提升幅度为变量 PsPrioritySeparation的值。
在前台应用完成它的等待操作时小幅提升它的优先级,以使它更有可能马上进入运行状态,有效改进前台应用的 响应时间特征 。
用户不能禁止这种优先级提升,甚至是在用户已利用 Win32的函数 SetThreadPriorityBoost禁止了其他的优先级提升策略时,也是如此。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
68
4,图形用户接口线程被唤醒后的优先级提升
拥有窗口的线程在被窗口活动唤醒 (如收到窗口消息 )时将得到一个 幅度为 2的额外优先级提升。
窗口系统 (Win32k.sys)在调用函数 KeSetEvent时实施这种优先级提升,KeSetEvent函数调用设臵一个事件,用于唤醒一个图形用户接口线程。
这种优先级提升的原因是改进交互应用的响应时间。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
69
5,对处理机饥饿线程的优先级提升
系统线程“平衡集管理器 (balance set manager)”
会每秒钟检查一次就绪队列,是否存在一直在就绪队列中排队超过 300个时钟中断间隔的线程。
如果找到这样的线程,平衡集管理器将把该线程的优先级提升到 15,并分配给它一个长度为正常值两倍的时间配额;
当被提升线程用完它的时间配额后,该线程的优先级立即衰减到它原来的基本优先级。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
70
如果在该线程结束前出现其他高优先级的就绪线程,该线程会被放回就绪队列,并在就绪队列中超过另外 300个时钟中断间隔后再次被提升优先级。
平衡集管理器只扫描 16个就绪线程。如果就绪队列中有更多的线程,它将记住暂停时的位臵,
并在下一次开始时从当前位臵开始扫描。
平衡集管理器在每次扫描时最多提升 10个线程的优先级。如果在一次扫描中已提升了 10个线程的优先级,平衡集管理器会停止本次扫描,
并在下一次开始时从当前位臵开始扫描。
这种算法并不能解决所有优先级倒臵的问题,
但它很有效。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
71
3.2.9 对称多处理机系统上的线程调度返回当 Windows 2000试图调度优先级最高的可执行线程时,有几个因素会影响到处理机的选择。 Windows 2000只保证一个优先级最高的线程处于运行状态 。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
72
1,亲合关系 (Affinity)
描述该线程可在哪些处理机上运行。
线程的亲合掩码是从进程的亲合掩码继承得到的。
缺省时,所有进程 (即所有线程 )的亲合掩码为系统中所有可用处理机的集合。应用程序通过调用 SetProcessAffinityMask或
SetThreadAffinityMask函数来指定亲合掩码;
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
73
2,线程的首选处理机和第二处理机
首选处理机 (ideal processor):线程运行时的偏好处理机;
– 线程创建后,Windows 2000系统不会修改线程的首选处理机设臵;
– 应用程序可通过 SetThreadIdealProcessor函数来修改线程的首选处理机。
第二处理机 (last processor):线程第二个选择的运行处理机;
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
74
3,就绪线程的运行处理机选择
当线程进入运行状态时,Windows 2000首先试图调度该线程到一个 空闲处理机 上运行。如果有多个空闲处理机,线程调度器的调度顺序为:
– 线程的 首选处理机
– 线程的 第二处理机
– 当前执行处理机 (即正在执行调度器代码的处理机 )。
– 如果这些处理机都不是空闲的,Windows 2000将依据 处理机标识从高到低扫描 系统中的空闲处理机状态,选择找到的第一个空闲处理机。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
75
如果线程进入就绪状态时,所有处理机都处于繁忙状态,
Windows 2000将检查一个处于运行状态或备用状态的线程,判断它是否可抢先。检查的顺序如下:
– 线程的首选处理机
– 线程的第二处理机
– 如果这两个处理机都不在线程的亲合掩码中,Windows 2000将依据活动处理机掩码选择该线程可运行的编号最大的处理机。
Windows 2000并不检查所有处理机上的运行线程和备用线程的优先级,而仅仅检查一个被选中处理机上的运行线程和备用线程的优先级。
如果在被选中的处理机上没有线程可被抢先,则新线程放入相应优先级的就绪队列,并等待调度执行。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
76
如果被选中的处理机已有一个线程处于备用状态 (即下一个在该处理机上运行的线程 ),并且该线程的优先级低于正在检查的线程,则正在检查的线程取代原处于备用状态的线程,成为该处理机的下一个运行线程。
如果已有一个线程正在被选中的处理机上运行,
Windows 2000将检查当前运行线程的优先级是否低于正在检查的线程;如果正在检查的线程优先级高,则标记当前运行线程为被抢先,系统会发出一个处理机间中断,以抢先正在运行的线程,让新线程在该处理机上运行。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
77
4,为特定的处理机调度线程
在多处理机系统,Windows 2000不能简单地从就绪队列中取第一个线程,它要在亲合掩码限制下寻找一个满足下列条件之一的线程。
– 线程的上一次运行是在该处理机上;
– 线程的首选处理机是该处理机;
– 处于就绪状态的时间超过 2个时间配额;
– 优先级大于等于 24;
如果 Windows 2000不能找到满足要求的线程,
它将从就绪队列的队首取第一个线程进入运行状态。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
78
5,最高优先级就绪线程可能不处于运行状态
有可能出现这种情况,一个比当前正在运行线程优先级更高的线程处于就绪状态,但不能立即抢先当前线程,进入运行状态。
例如:假设 0号处理机上正运行着一个可在任何处理机上运行的优先级为 8的线程,1号处理机上正运行着一个可在任何处理机上 运行的优先级为 4的线程;这时一个只能在 0号处理机上运行的优先级为 6的线程进入就绪状态。
在这种情况下,优先级为 6的线程只能等待 0号处理机上优先级为 8的线程结束。因为 Windows 2000不会为了让优先级为 6的线程在 0号处理机上运行,而把优先级为 8的线程从 0
号处理机移到 1号处理机。即 0号处理机上的优先级为 8的线程不会抢先 1号处理机上优先级为 4的线程。
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
79
3.2.10 空闲线程
如果在一个处理机上没有可运行的线程,
Windows 2000/XP会调度相应处理机对应的空闲线程。
由于在多处理机系统中可能两个处理机同时运行空闲线程,所以系统中的每个处理机都有一个对应的空闲线程。
Windows 2000/XP给空闲线程指定的线程优先级为 0,该空闲线程只在没有其他线程要运行时才运行。
返回
Mi
cr
os
of
t?
W
indow
s
2
00
0/X
P
80
空闲线程的功能
空闲线程的功能就是在一个循环中检测是否有要进行的工作。其基本的控制流程如下:
– 处理所有待处理的 中断请求 。
– 检查是否有待处理的 DPC请求 。如果有,则清除相应软中断并执行 DPC。
– 检查是否有 就绪线程 可进入运行状态。如果有,调度相应线程进入运行状态。
– 调用硬件抽象层的处理机空闲例程,执行相应的 电源管理 功能。