125
1 第 3 第 第第 第第第第第第第第

第 3 讲 进程、线程和处理机管理

  • Upload
    delila

  • View
    175

  • Download
    0

Embed Size (px)

DESCRIPTION

第 3 讲 进程、线程和处理机管理. 3.1 进程 3.2 进程控制 3.3 线程 3.4 进程互斥与同步 3.5 进程间通信 3.6 死锁问题 3.7 处理器调度概述 3.8 调度算法 3.9 Windows 2000/XP 的线程调度. 3.1 进程. 进程 处理器管理的基本单元 进程执行方式: 顺序 与 并发 顺序执行的特征 顺序性、封闭性、可再现性 并发执行的特点 间断性、非封闭性、无可再现性  因为 共享资源 的影响! 两进程 Pi, Pj 并发的条件,三者之一满足即可 Ri ∩ Wj = 空 - PowerPoint PPT Presentation

Citation preview

1

第 3 讲 进程、线程和处理机管理

2

3.1 进程 3.2 进程控制 3.3 线程 3.4 进程互斥与同步 3.5 进程间通信 3.6 死锁问题 3.7 处理器调度概述 3.8 调度算法 3.9 Windows 2000/XP 的线程调度

3

3.1 进程 进程 处理器管理的基本单元 进程执行方式:顺序 与 并发

顺序执行的特征 顺序性、封闭性、可再现性 并发执行的特点 间断性、非封闭性、无可再现性因

为共享资源共享资源的影响! 两进程 Pi, Pj 并发的条件,三者之一满足即可

Ri ∩ Wj = 空 Wi ∩ Rj = 空 Wi ∩ Wj = 空

4

定义 进程不同于程序

进程是动态的 进程是暂时的 进程组成更为复杂 二者密切相关 并不是所有代码的执行过程都属于某一个进程:处理器调度器

进程控制块 PCB 操作系统维护 记录了进程相关的信息 OS 可以通过 PCB 控制进程,并将处于同一状态的进程的进程

块组织到一起:链表、索引表

进程的定义与描述

5

PCB 组成

进程描述信息 进程标示符、进程名、用户标示符、进程组等

进程控制信息 当前状态、优先级、代码执行入口地址、程序的外

存地址、运行统计信息、进程阻塞原因等 资源占用信息

占用的系统资源列表 处理器现场保护结构

保存寄存器值等

6

进程上下文

进程执行活动全过程的静态描述 用户级上下文

进程的用户地址空间,用户正文段、数据段、用户栈

寄存器级上下文 程序寄存器、处理器状态寄存器、栈指针等的值

系统级上下文 进程的静态部分、由核心栈等构成的动态部分

7

进程的状态转换

模型一:两状态进程模型 状态

运行状态:占用处理机资源; 暂停状态:等待进程调度分配处理机资源;

Not-Runni ng Runni ng

Di spatch

Pause

Enter Exi t

8

转换 进程创建 (Enter) :系统创建进程,形成 PCB ,分

配所需资源,排入暂停进程表 ( 可为一个队列 ) ; 调度运行 (Dispatch):从暂停进程表中选择一个进

程 ( 要求已完成 I/O 操作 ) ,进入运行状态; 暂停运行 (Pause):用完时间片或启动 I/O 操作后,放弃处理机,进入暂停进程表;

进程结束 (Exit):进程运行中止;

9

模型二:五状态进程模型 两状态模型无法区分暂停进程表中的可运行和阻塞,

五状态模型就是对暂停状态的细化。 运行:处于此状态的进程的数目小于等于 CPU 数目 就绪:已获除处理机外的所需资源,只要分配 CPU

就可执行 阻塞:条件满足之前无法继续执行 创建:进程刚创建,但还不能运行,如资源不足等 退出:回收 PCB 之外的其他资源,并让其他进程从

PCB 中收集有关信息(如记帐,将退出码 exit code传递给父进程)

10

状态转换 创建新进程 收容:收容一个新进程,进入就绪状态 调度运行 释放:正常退出 Exit 和异常退出 abort(执行超时或内存不够,非法指令或地址, I/O失败,被其他进程所终止);就绪或阻塞到结束可能的原因有:如父进程可在任何时间中止子进程;

超时 事件等待 事件出现

创建

就绪 运行 退出

阻塞创建进程

提交

调度

超时

释放

等待事件事件出现

11

一个重要问题:一个事件出现时如何检查阻塞进程表中的进程状态

图 3-2 单个队列对性能影响很大

CPU提交

释放调度

超时

就绪队列

等待队列等待事件事件

出现

进程执行

12

图图 3-3 3-3 按事件类型排成多个队列,按事件类型排成多个队列,可以按多个优先可以按多个优先级来划分队列,如:时间片用完-级来划分队列,如:时间片用完- >>低优,低优, I/OI/O 完完成-成- >> 中优,页面调入完成-中优,页面调入完成- >>高优高优

CPU提交

释放调度

超时

就绪队列

等待队列 1等待事件 1事件 1出现

进程执行

等待事件 2

等待队列 2

事件 2出现

13

模型三:挂起进程模型 五状态进程模型没有区分进程的地址空间 内存?外存? 进程优先级,低优先级等待时间长,应换至外存区分进程地

址空间 提高处理机效率:就绪进程表为空时,要提交新进程,以提高处理机效率;

为运行进程提供足够内存:资源紧张时,暂停某些进程,如: CPU繁忙(或实时任务执行),内存紧张

用于调试:在调试时,挂起被调试进程(从而对其地址空间进行读写)

14

意义有变化或新的状态 就绪状态:进程在内存,可立即运行 阻塞状态:在内存,等待时间出现 阻塞挂起:在外存等待某事件出现 就绪挂起:在外存,只要进入内存即可运行

15

新状态转换: 挂起(调出)、激活(调入) 意义有变化的状态转换: 事件的出现、收容

图 3-4 单进程挂起 图 3-5 双进程挂起

16

3.2 进程控制 进程的创建与退出

子进程可继承父进程部分属性 按子进程是否覆盖父进程或是否加载新程序,调用

不同的系统调用 进程终止

产生新进程 不产生新进程

复制现有进程的上下文 Fork( 新进程的系统上下文会有所不同 )

----

加载程序 Spawn( 创建新进程并加载新程序 )

Exec( 加载新程序并覆盖自身 )

17

进程的阻塞与唤醒 阻塞:等待某个事件引起 阻塞状态 唤醒:事件出现 就绪状态 Unix 系统中

sleep 、 pause 、 wait 、 kill等 用于阻塞 Windows NT、 Windows2000/XP 中,处理器调度

对象为线程 线程控制块中的挂起记数, 挂起加 1 ,激活减 1 挂起: Windows NT 中的 SuspendThread 可挂起指定的线

程 DWORD SuspendThread( HANDLE hThread); 激活: Windows NT中的 ResumeThread 可恢复指定线

程的执行; DWORD ResumeThread( HANDLE hThread);

18

Windows2000/XP 进程管理

进程是系统资源分配的基本单位 将进程作为对象来管理,进程对象句柄 进程对象

进程标识 资源访问令牌 进程的基本优先级 默认亲合处理器集合

2000/xp 中,基本的进程功能被放置在 win32子系统中,另外两个子系统用其实现自身的功能; p98图 3-6

19

Win32 进程信息描述 执行体进程块( EPROCESS)

描述进程的基本信息 指向其他与进程控制相关的数据结构 线程列表块、虚拟地址空间描述表、对象句柄列表

p99 3-7

20

Win32子系统的进程控制 CreateProcess 创建进程及主线程,执行指定地程序

创建时可集成父进程属性,如打开的文件句柄各种对象的句柄、环境变量、当前目录等

不能继承:优先权类、内存句柄等 ExitProcess

退出进程,结束其所有的线程,操作是完整的 TerminateProcess

退出进程并结束其所有线程,但主要是异常时使用,操作不完整;

21

引入线程的目的是简化线程间的通信,以小的开销来提高进程的并发程度。

进程提高计算机资源利用率,但并发时进程的切换开销较大,同时通信效率较低;

概念:一个动态对象,处理器调度的基本单位,表示进程中的一个控制点,执行一系列的指令;

进程仍是资源分配的单位,但进程内允许有多个线程并发执行。

不同于进程 同一进程内的线程可访问整个进程的所有资源,通

信较进程方便; 许多上下文相同同一进程内的线程转换更简便

3.3 线程

22

同进程内的线程区别 线程状态:运行、挂起、就绪… 寄存器上下文 堆栈等必不可少的执行环境

线程的优点 创建时间短 终止时间短 同进程内的线程切换时间短 通过共享内存及文件资源方式通信,通信不需通过内核

进行;

23

OS 对线程的实现方式 内核线程:依赖于 OS 核心,由内核的内部需求进行创

建和撤销,用来执行一个指定的函数。一个线程发起系统调用而阻塞,不会影响其他线程。时间片分配给线程,所以多线程的进程获得更多 CPU时间。

用户线程:不依赖于 OS 核心(内核不了解用户线程的存在),应用进程利用线程库提供创建、同步、调度和管理线程的函数来控制用户线程。调度由应用软件内部进行,通常采用非抢先式和更简单的规则,也无需用户态 / 核心态切换,所以速度特别快。一个线程发起系统调用而阻塞,则整个进程在等待。时间片分配给进程,多线程则每个线程就慢。

轻权进程:内核支持的用户线程。一个进程可有一个或多个轻权进程,每个轻权进程由一个单独的内核线程来支持。结合了内核线程和用户线程的优点

24

线程与进程的比较

地址空间和其他资源:进程间相互独立,同一进程的各线程间共享-某进程内的线程在其他进程不可见(如打开文件)

通信:进程间通信 -IPC ,线程间可以直接读写进程数据段(如全局变量)来进行通信--需要进程同步和互斥手段的辅助,以保证数据的一致性

调度和切换:线程上下文切换比进程上下文切换要快得多;

25

单线程进程模型

进程控制块

用户地址空间

用户堆栈

内核堆栈

多线程进程模型

进程控制块

用户地址空间

用户堆栈

内核堆栈

线程控制块

线程

用户堆栈

内核堆栈

线程控制块

线程

用户堆栈

内核堆栈

线程控制块

线程

进程与线程的比较

26

Windows2000/XP 线程

采用内核线程机制 线程上下文

寄存器 线程环境块 核心栈 用户栈

状态与进程类似,在就绪与运行之间添加了备用状态,以优化线程的抢先特征。

27

线程状态

就绪状态:已获得除处理机外的所需资源,等待执行。 备用状态:特定处理器的执行对象,系统中每个处理器上只能有一个处于备用状态的线程。

运行状态:完成描述表切换,线程进入运行状态,直到内核抢先、时间片用完、线程终止或进行等待状态。

等待状态:线程等待对象句柄,以同步它的执行。等待结束时,根据优先级进入运行、就绪状态。

转换状态:准备执行而其内核堆栈处于外存时,线程进入转换状态;当其内核堆栈调回内存,线程进入就绪状态。

终止状态:执行完就进入终止状态;如执行体有一指向线程对象的指针,可将线程对象重新初始化,并再次使用。

28

29

Win32子系统的线程控制 CreateThread()函数在调用进程的地址空间上创建一

个线程,以执行指定的函数;返回值为所创建线程的句柄。

ExitThread()函数用于结束本线程。 SuspendThread()函数用于挂起指定的线程。 ResumeThread()函数递减指定线程的挂起计数,挂起

计数为 0 时,线程恢复执行。

30

3.4 进程互斥和同步 同步:多进程中发生的事件存在时序关系 互斥:由于共享资源所要求的排他性,要竞争 互斥算法

平等协商 or 集中管理(进程管理者) 临界资源:需互斥使用的硬件或软件(如外设、共享代

码段、共享数据结构),多个进程在对其进行访问时(关键是进行写入或修改),必须互斥地进行-有些共享资源可以同时访问,如只读数据

共享变量的修改冲突

一个火车订票系统,两个终端,运行 T1、 T2进程

T1 : T2:

... ...

Read(x); Read(x);

if x>=1 then if x>=1 then

x:=x-1; x:=x-1;write(x); write(x);

... ...

操作顺序冲突

有 3 个进程: get, copy 和 put ,它们对 4 个存储区域 f 、 s 、t 和 g 进行操作。

get copy put

ff ttss gg

有 6种可能的操作顺序,只有一种结果是正确的。

f s t g 结果

初始状态 3,4,...,m 2 2 (1,2)

g,c,p 4,5,...,m 3 3 (1,2,3) 正确

g,p,c 4,5,...,m 3 3 (1,2,2) 错误

c,g,p 4,5,...,m 3 2 (1,2,2) 错误

c,p,g 4,5,...,m 3 2 (1,2,2) 错误

p,c,g 4,5,...,m 3 2 (1,2,2) 错误

p,g,c 4,5,...,m 3 3 (1,2,2) 错误

34

相互感知的程度 交互关系 一个进程对其他进程的影响

潜在的控制问题

相互不感知 ( 完全不了解其它进程的存在 )

竞争 (competition)

一个进程的操作对其他进程的结果无影响

互斥,死锁(可释放的资源),饥饿

间接感知 (双方都与第三方交互,如共享资源 )

通过共享进行协作

一个进程的结果依赖于从其他进程获得的信息

互斥,死锁(可释放的资源),饥饿,数据一致性

直接感知 (双方直接交互,如通信 )

通过通信进行协作

一个进程的结果依赖于从其他进程获得的信息

死锁,饥饿

进程的交互关系:可按相互感知的程度分为三类

35

互斥 (mutual exclusion) ,死锁 (deadlock) ,饥饿(starvation)

互斥,指多个进程不能同时使用同一个资源; 死锁,指多个进程互不相让,都得不到足够的资

源; 饥饿,指一个进程一直得不到资源而其他进程可能轮流占用资源

间接制约:进行竞争-独占分配到的部分或全部共享资源,“互斥”

直接制约:进行协作-等待来自其他进程的信息,“同步”

互斥算法

36

解决之道 互斥使用:多进程不能同时使用同一资源 避免死锁:避免多个进程互不相让 避免饥饿:避免某些进程长期得不到资源或得到资源的概率很小

37

访问临界资源的过程 四步 进入区 (entry section) :在进入临界区之前检查可否进入临界区的一段代码。如果可以进入临界区,通常设置相应“正在访问临界区”标志

临界区 (critical section) :在每个进程中,访问临界资源的一段代码

退出区 (exit section) :用于将“正在访问临界区”标志清除

剩余区 (remainder section) :代码中的其余部分

进入区

退出区 临界区

剩余区

临界区的访问过程

39

同步机制应遵循的准则 空闲则入

最多一个进程位于临界区,其他进程均不处于临界区; 忙则等待

已有进程处于其临界区; 有限等待

等待进入临界区的进程不能无限期“死等”; 让权等待

不能进入临界区的进程,应释放 CPU(如转换到阻塞状态)

40

进程互斥的软件方法 基本思路

在进入区检查和设置一些标志,如已有进程进入临界区,则在进入区循环检查并等待;在退出区修改标志。

主要问题 设置什么标志 如何检查标志

41

单标志法

一个标志 turn ,描述允许进入临界区的进程标识 在进入区循环检查是否允许本进程进入: turn 为 i 时,进程 Pi 可

进入; 在退出区修改允许进入进程标识:进程 Pi退出时,改 turn 为进程

Pj 的标识 j ; 两个进程 Pi, Pj ,其中的 Pi

while (turn != i) ;临界区

turn = j ;剩余区

等待 j 释放资源

j 释放资源, I 进入临界区

i 释放资源,置标志为 j

42

算法可保证任何时刻最多只有一个进程在临界区 缺点

强制轮流进入临界区,没有考虑进程的实际需要; 容易造成资源利用不充分:在 Pi出让临界区之后, Pj使用临界区之前, Pi 不可能再次使用临界区;

如何避免这些缺点???

43

双标志、先检查算法

设立一个标志数组 flag[] :描述进程是否在临界区,初值均为 FALSE。 先检查,后修改:在进入区检查另一个进程是否在临界

区,不在时修改本进程在临界区的标志;进入临界区; 在退出区修改本进程在临界区的标志;

while (flag[j]) ; <a>flag[i] = TRUE ; <b>临界区flag[i] = FALSE;剩余区

44

优点:不用交替进入,可连续使用; 缺点

Pi 和 Pj 可能同时进入临界区,违犯最多只有一个进程在临界区的要求;

按序列 "Pi<a> Pj<a> Pi<b> Pj<b>" 执行时,会同时进入。在检查对方 flag 之后和切换自己 flag 之前有一段时间,结果都检查通过。问题出在检查和修改操作不能连续进行。

45

双标志、后检查算法

解决前一算法的问题 保证检查与修改操作之间不出现

间隔仅软件方法无法实现 修改标志的含义

类似于前一算法,区别在于本算法先修改后检查。可防止两个进程同时进入临界区。

flag[i] = TRUE;while (flag[j]) ;临界区

flag[i] = FALSE;

剩余区

46

缺点: Pi 和 Pj 可能都进入不了临界区 按序列“ Pi<a> Pj<a> Pi<b> Pj<b>”执行时,

都进不了临界区。即:切换自己 flag 之后和检查对方 flag 之前有一段时间,结果都切换 flag ,都检查不通过。

47

先修改、后检查、后修改者等待 结合算法 1 和算法 3 ,是正确的算法 turn=j ,描述可进入的进程(同时修改标志时) 在进入区先修改后检查,并检查并发修改的先后:

检查对方 flag ,如不在临界区则自己进入-空闲则入 否则再检查 turn :保存的是较晚的一次赋值,则较晚的

进程等待,较早的进程进入-先到先进,后到等待flag[ii] = TRUE; turn = jj;

while (TRUE==flag[jj]&&turn == jj) ;临界区

flag[ii] = FALSE;

剩余区

48

flag[ii] = TRUE; turn = ii;while (TRUE==flag[jj]&&turn == jj) ;临界区

flag[ii] = FALSE;

剩余区flag[jj] = TRUE; turn = jj;

while (TRUE==flag[ii]&&turn == ii) ;临界区

flag[jj] = FALSE;

剩余区

如果将算法改为如下方法,将产生什么样的效果?

会不会同时进入?会不会死锁?Turn很重要!

49

进程互斥的硬件方法

完全利用软件方法,有很大局限性(如不适于多进程),现在已很少采用。

在平等协商时,可利用某些硬件指令--其读写操作由一条指令完成,因而保证读操作与写操作不被打断;

50

Test-and-Set 指令

该指令读出标志后设置为 TRUEboolean TS(boolean *lock) { boolean old ; old = *lock; *lock = TRUE ; return old ;}

lock 表示资源的两种状态: TRUE 表示正被占用, FALSE 表示空闲

51

利用 TS 指令的互斥算法

每个临界资源设置一个公共布尔变量 lock,初值为 FALSE

在进入区利用 TS 进行检查:有进程在临界区时,重复检查;直到其它进程退出时,检查通过;

while TS(&lock);

lock = FALSE;

临界区

剩余区

52

Swap 指令

交换两个字(字节)的内容

void SWAP(int *a , int *b) { int temp ; temp = *a ; *a = *b ; *b = temp ;}

53

利用 Swap实现进程互斥 每个临界资源设置一个公共布尔变量 lock,初值为 FALS

E。每个进程设置一个私有布尔变量 key 进程要使用临界资源时将会首先将自己的 key置为 true

Lock值 Key 值 交换后FalseFalse truetrue 可用可用True True 正在使用false False /

true false /

key = TRUE;key = TRUE;do{ SWAP(&lock, &key);} while(keykey);

lock = FALSE;

临界区

剩余区

54

硬件方法的优点 适用于任意数目的进程,在单处理器或多处理器上 简单,容易验证其正确性 可以支持进程内存在多个临界区,为每个临界区设立一

个布尔变量 硬件方法的缺点

等待要耗费 CPU时间,不能实现 "让权等待 " 可能 "饥饿 " :从等待进程中随机选择一个进入临界区,

有的进程可能一直选不上 可能死锁

55

信号量信号量

互斥算法都存在问题,它们是平等进程间的一种协商机制,需要一个地位高于进程的管理者来解决公有资源的使用问题。

OS 可从进程管理者的角度来处理互斥的问题,信号量就是 OS提供的管理公有资源的有效手段。

信号量代表可用资源实体的数量

56

信号量和 P 、 V 原语 荷兰学者 Dijkstra提出一种有效的进程同步机制 P 、 V来自荷兰语的 test(proberen) 和 increment (verhog

en) 每个信号量 s除一个整数值 s.count(计数)外,还有一个

进程等待队列 s.queue ,其中是阻塞在该信号量的各个进程的标识

信号量只能通过初始化和两个标准的原语来访问 原语作为 OS 核心代码执行,不受进程调度的打断 初始化指定一个非负整数值,表示空闲资源总数(又称为 " 资源信

号量 ")--若为非负值表示当前的空闲资源数,若为负值其绝对值表示当前等待临界区的进程数

" 二进制信号量 " :只允许信号量取 0 或 1 值

57

P 原语相当于进入区, V 原语相当于退出区操作 P 原语描述函数 wait(s)

--s.count ; // 申请一个资源if (s.count<0) //没有空闲资源,有 s.count 个进程等 // 待该资源,应该排队{ 调用进程进入等待队列 s.queue 排队 阻塞调用进程进行等待}

58

V 原语描述函数 signal(s) V 原语通常唤醒进程等待队列中的头一个进程

++s.count ; //释放一个资源;if(s.count<=0) // 表示有进程处于阻塞状态,调度该进程{ 从等待队列 s.queue 中取出一个进程; 进程 P 进入就绪队列 ;}

59

利用信号量实现互斥 为临界资源设置一个互斥信号量mutex(MUTual Exclusion) ,其初值为 1 ;在每个进程中将临界区代码置于 P(mutex) 和V(mutex) 原语之间

必须成对使用 P 和 V 原语:遗漏 P 原语则不能保证互斥访问,遗漏V 原语则不能在使用临界资源之后将其释放(给其他等待的进程);

P 、 V 原语不能次序错误、重复或遗漏

V(mutex) ;临界区

剩余区

P(mutex) ;

60

利用信号量来描述前趋关系

前趋关系 并发执行的进程 P1 和 P2 中,分别有代码 C1 和 C2 ,

要求 C1在 C2开始前完成; 进程间同步执行

为每个前趋关系设置一个互斥信号量 S12 ,其初值为 0 , P1 执行到 V(S12) 后, P2 才会结束 P(S12) 的执行。

P1

C1

V(S12) C2

P(S12)

P2

61

信号量集

信号量集用于同时需要多个资源时的信号量操作;

AND 型信号量集 AND 型信号量集用于同时需要多种资源且每种占

用一个时的信号量操作; 一段处理代码需要同时获取两个或多个临界资

源――可能死锁:各进程分别获得部分临界资源,然后等待其余的临界资源,“各不相让”

62

AND 型信号量集

基本思想 在一个原语中,将一段代码同时需要的多个临界资源,要么全部分配给它,要么一个都不分配。称为 Swait(Simultaneous Wait)。在 Swait 时,各个信号量的次序并不重要,虽然会影响进程归入哪个阻塞队列,但是由于是对资源全部分配或不分配,所以总有进程获得全部资源并在推进之后释放资源,因此不会死锁。

Swait(S1, S2, …, Sn) //P 原语; { while (TRUE) {

if (S1 >=1 && S2 >= 1 && … && Sn >= 1) { // 满足资源要求时的处理; for (i = 1; i <= n; ++i) - - Si; // 注:与 wait 的处理不同,这里是在确信可满足 // 资源要求时,才进行减 1 操作; break; } else{ // 某些资源不够时的处理; 调用进程进入第一个小于 1 信号量的等待队列 Sj.queue; 阻塞调用进程 ;

} } }

Ssignal(S1, S2, …, Sn) { for (i = 1; i <= n; ++i) { ++Si; //释放占用的资源; for (each process P waiting in Si.queue) //检查每种资源的等待队列的所有进程; { 从等待队列 Si.queue 中取出进程 P; if ( 判断进程 P 是否通过 Swait 中的测试 ) // 注:与 signal 不同,这里要进行重新判断; { // 通过检查(资源够用)时的处理; 进程 P 进入就绪队列 ; } else{//// 未通过检查未通过检查 (( 资源不够用资源不够用 )) 时的处理;时的处理;

进程进程 PP 进入某等待队列;进入某等待队列; } } } }

65

一般“信号量集”

一般信号量集用于同时需要多种资源、每种占用的数目不同、且可分配的资源还存在一个临界值时的处理;

一次需要 N个某类临界资源时,就要进行 N次wait 操作--低效又可能死锁

基本思想:在 AND 型信号量集的基础上进行扩充:进程对信号量 Si 的测试值为 ti(用于信号量的判断,即 Si >= ti ,表示资源数量低于 ti 时,便不予分配),占用值为 di(用于信号量的增减,即 Si = Si - di 和 Si = Si + di)

Swait(S1, t1, d1 ; ... ; Sn, tn, dn) ; Ssignal(S1, d1 ; ... ; Sn, dn) ;

66

一般 " 信号量集 " 的几种特定情况: Swait(S, d, d) 表示每次申请 d 个资源,当少于 d 个时,便不分配;( S<d 时,可能满足其他进程需要)

Swait(S, 1, 1) 表示互斥信号量; 如何理解? Swait(S, 1, 0) 作为一个可控开关

当 S>=1 时,允许多个进程进入临界区; 当 S=0 时,禁止任何进程进入临界区;

一般 " 信号量集 " 未必成对使用 Swait 和 Ssignal:如:一起申请,但不一起释放;

67

经典进程同步问题 主要问题:如何选择信号量、如何安排原语顺序 生产者-消费者问题

问题描述:若干进程通过有限的共享缓冲区交换数据。其中, "生产者 " 进程不断写入,而 " 消费者 " 进程不断读出;共享缓冲区共有 N 个;任何时刻只能有一个进程可对共享缓冲区进行操作。

♯ ♯♯ ♯

♯ ♯♯ ♯

共享缓冲区

生产指针 消费指针生产者 1

...

消费者 1

...

满 空 指针移动方向

生产者 2

生产者 n

消费者 2

消费者 n

68

采用信号量机制: full是 " 满 " 数目,初值为 0 , empty 是 " 空 " 数目,初值为 N。实际上, full和 empty 是同一个含义: full + empty == N

mutex 用于访问缓冲区时的互斥,初值是 1 每个进程中各个 P 操作的次序是重要的:先检查

资源数目,再检查是否互斥――否则可能死锁( 为什么? )

69

消费者生产者P(empty) ;P(mutex) ; // 进入区 写入;V(mutex) ;V(full) ; //退出区

P(full) ;P(mutex) ; // 进入区 读出;V(mutex) ;V(empty) ; //退出区

采用 AND 信号量集: Swait(empty, mutex), Ssignal(full, mutex) , …

70

问题描述:对共享资源的读写操作,任一时刻“写者”最多只允许一个,而“读者”则允许多个

“读-写”互斥, “写-写”互斥, "读-读 "允许

读者-写者问题

71

采用信号量机制: Wmutex 表示 "允许写 " ,初值是 1。 公共变量 Rcount 表示“正在读”的进程数,初值是 0 ; Rmutex 表示对 Rcount 的互斥操作,初值是 1。

P(Rmutex); if(Rcount == 0)

P(Wmutex); ++Rcount;V(Rmutex); read;

P(Rmutex); --Rcount; if(Rcount == 0)

V(Wmutex);V(Rmutex);

读者

P(Wmutex); write;

V(Wmutex);

写者

72

采用一般“信号量集”机制 增加一个限制条件:同时读的 "读者 "最多 R 个 Wmutex 表示 "允许写 " ,初值是 1 Rcount 表示 "允许读者数目 " ,初值为 R

Swait(Rcount, 1, 1; Wmutex, 1, 0); read;Ssignal(Rcount, 1);

读者

Swait(Wmutex, 1, 1; Rcount, R, 0); write;

Ssignal(Wmutex, 1);

写者

73

管程

用信号量可实现进程间的同步,但由于信号量的控制分布在整个程序中,其正确性分析很困难。

管程是管理进程间同步的机制,它保证进程互斥地访问共享变量,并方便地阻塞和唤醒进程。

管程可以函数库的形式实现。相比之下,管程比信号量好控制。

74

信号量同步的缺点 同步操作分散:信号量机制中,同步操作分散在各个进

程中,使用不当就可能导致各进程死锁(如 P 、 V 操作的次序错误、重复或遗漏)

易读性差:要了解对于一组共享变量及信号量的操作是否正确,必须通读整个系统或者并发程序;

不利于修改和维护:各模块的独立性差,任一组变量或一段代码的修改都可能影响全局;

正确性难以保证:操作系统或并发程序通常很大,很难保证这样一个复杂的系统没有逻辑错误;

75

管程的引入 1973 年, Hoare 和 Hanson 所提出; 基本思想:把信号量及其操作原语封装在一个对象内部。

即:将共享变量及对共享变量能够进行的所有操作集中在一个模块中。

管程的定义:是关于共享资源的数据结构及一组针对该资源的操作过程所构成的软件模块。

76

优点 管程可增强模块的独立性:系统按资源管理的观点分解

成若干模块,用数据表示抽象系统资源,同时分析了共享资源和专用资源在管理上的差别,按不同的管理方式定义模块的类型和结构,使同步操作相对集中,从而增加了模块的相对独立性;

引入管程可提高代码的可读性,便于修改和维护,正确性易于保证:采用集中式同步机制。一个操作系统或并发程序由若干个这样的模块所构成,一个模块通常较短,模块之间关系清晰。

77

管程的主要特性 模块化:一个管程是一个基本程序单位,可以单独编译; 抽象数据类型:管程是一种特殊的数据类型,其中不仅

有数据,而且有对数据进行操作的代码 信息封装:管程是半透明的,管程中的外部过程(函

数)实现了某些功能,至于这些功能是怎样实现的,在其外部则是不可见的;

78

管程的实现要素 管程中的共享变量在管程外部是不可见的,外部只能通

过调用管程中所说明的外部过程(函数)来间接地访问管程中的共享变量;

为了保证管程共享变量的数据完整性,规定管程互斥进入;

管程通常是用来管理资源的,因而在管程中应当设有进程等待队列以及相应的等待及唤醒操作;

79

管程中的多个进程进入 当一个进入管程的进程执行等待操作时,它应当释放管

程的互斥权;当一个进入管程的进程执行唤醒操作时(如P唤醒Q),管程中便存在两个同时处于活动状态的进程。

管程中的唤醒切换方法: P 等待 Q继续,直到 Q 等待或退出; Q 等待 P继续,直到 P 等待或退出; 规定唤醒为管程中最后一个可执行的操作;规定唤醒为管程中最后一个可执行的操作;

80

入口等待队列:因为管程是互斥进入的,所以当一个进程试图进入一个巳被占用的管程时它应当在管程的入口处等待,因而在管程的入口处应当有一个进程等待队列,称作入口等待队列。

紧急等待队列:如果进程P唤醒进程Q,则P等待Q继续,如果进程Q在执行又唤醒进程R,则Q等待R继续, ... ,如此,在管程内部,由于执行唤醒操作,可能会出现多个等待进程(已被唤醒,但由于管程的互斥进入而等待),因而还需要有一个进程等待队列,这个等待队列被称为紧急等待队列。它的优先级应当高于入口等待队列的优先级。

81

管程与进程的区别 OS 中设置进程是为了描述程序的动态执行过程 设置管程则是为了实现进程的同步,协调进程的相互关

系和对共享资源进行访问; OS 维护的进程数据结构是进程控制块,而与管程相关

的数据结构是等待队列; 管程可被进程调用 管程与 OS 中的共享资源有关,没有创建和撤销,而进

程有创建和撤销;

82

Windows 2000/xp 的进程同步机制 互斥对象、信号量对象、事件对象及相应的系统调用 用于进程及线程同步; 本质上相同,但适用的场合、效率不同; 不同进程中用同样的对象名称创建或打开对象,从而获得该对象在本进程的句柄;

83

Windows 2000/xp提供统一的等待操作 WaitForSingleObject()

在指定时间内等待指定对象为可用状态 WaitForMultipleObjects()

指定时间内等待多个对象为可用状态

84

互斥对象 互斥信号量,任一时刻只能被一个线程使用 CreateMutex 、 OpenMutex 、 ReleaseMutex

信号量对象 资源信号量,初值在 0 到最大值之间,用于限制并发访问的线

程数量 CreateSemaphore 、 OpenSemaphore 、 ReleaseSemaph

ore 事件对象

相当于触发器,可用于通知一个或多个线程某事件出现 CreateEvent 、 OpenEvent 、 SetEvent 、 ResetEvent 、 P

aulseEvent

85

Windows 提供的与进程同步相关的机制 临界区:只用于同一进程内的资源

InitializeCriticalSection 初始化临界区对象; EnterCriticalSection 等待临界区使用权,得到使用权时返回;

TryEnterCriticalSection 非等待方式申请临界区的使用权;申请失败时,返回 0 ;

LeaveCriticalSection释放临界区的使用权; DeleteCriticalSection释放与临界区对象相关的所

有系统资源。

86

互斥变量:相当于硬件指令,用于对整型变量的操作,避免线程间切换对操作连续性的影响。

InterlockedExchange 先读后写原子操作; InterlockedExchangePointer 对指针的原子操作; InterlockedCompareExchange依据比较结果进行赋值的原子操作;

InterlockedCompareExchangePointer 对指针的 CompareExchange 原子操作;

InterlockedExchangeAdd 先加后存结果的原子操作;

InterlockedDecrement 先减 1 后存结果的原子操作; InterlockedIncrement 先加 1 后存结果的原子操作。

87

实验一 利用 windows 提供的线程、进程创建接口,设

计一个程序,能够动态创建进程及 n 个线程; 程序能够对进程、线程的运行状态进行控制,如

创建、挂起、终止等; 用多个线程表示读者和写者,用信号量机制实现读者优先问题;

88

3.5 进程间通信 解决进程间的信息交流问题 按通信量

低级通信:进程间传递状态和整数值,包括互斥和同步间采用的信号量机制; 快速,但信息量小,编程复杂

高级通信:可传送任意数据,包括共享存储区、管道、消息等

按是否有第三方周转 直接通信:发送方指定接收方地址或标识,多播;接收

方可接收任意方法来的数据,可获取发送方地址; 间接通信:借助双方之外的共享数据结构作为通信中转,接收方、发送方数目任意;

89

Windows 2000/XP 的信号

信号 进程与外界的一种低级通信方式,相当于软中断; 进程可发送信号,每个进程都有指定信号处理例程; 信号通信是单向和异步的; Windows 2000/XP 有两组与信号相关的系统调用,分别

处理不同的信号

90

信号名 说明CTRL_C_EVENT 当用户按下了 CTRL+C, 或者由 GenerateCon

soleCtrlEvent API 发出CTRL_BREAK_EVENT 用户按下 CTRL+BREAK, 或者由 GenerateCo

nsoleCtrlEvent API 发出 .CTRL_CLOSE_EVENT 当用户关闭控制台时系统向该控制台的所有进

程发送的控制台关闭信号CTRL_LOGOFF_EVENT 用户退出系统时系统向所有控制台进程发送的

退出信号,,但是不能决定是哪个用户CTRL_SHUTDOWN_EVENT 系统关闭时向所有控制台进程发送的关机信号

BOOL SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine, // 回调函数BOOL Add // 表示添加还是删除) ;定义 / 取消本进程的信号处理例程GenerateConsoleCtrlEvent 发送信号到与本进程共享同一控制台的控制台进程组

91

CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT 和 CTRL_SHUTDOWN_EVENT 通常被用来处理一些程序的清理工作,然后调用 ExitProcess API。

这三个事件有超时机制, CTRL_CLOSE_EVENT 是 5 秒,另外两个是 20 秒。如果程序超时,系统将会弹出结束进程的对话框。如果用户选择了结束进程,任何清理工作都不会做,所以应该在超时时间内完成清理工作。

下面是一个回调函数的例子 http://soft.yesky.com/SoftChannel/72342376189788160/20030608/1706043.shtml

BOOL WINAPI ConsoleHandler( DWORD CEvent) {char mesg[128] ;switch( CEvent) {case CTRL_C_EVENT:

MessageBox(NULL,"CTRL+C received!","CEvent",MB_OK); break;case CTRL_BREAK_EVENT:

MessageBox(NULL,"CTRL+BREAK received!","CEvent",MB_OK);

break;case CTRL_CLOSE_EVENT:

MessageBox(NULL,"Program being closed!","CEvent",MB_OK);

break;case CTRL_LOGOFF_EVENT:

MessageBox(NULL,"User is logging off!","CEvent",MB_OK);break;

case CTRL_SHUTDOWN_EVENT:MessageBox(NULL,"User is logging off!","CEvent",MB_OK);break;

}return TRUE ;

}

设置处理例程if ( SetConsoleCtrlHandler (( PHANDLER_ROUTINE ) ConsoleHandler,TRUE ) ==FALSE ){

// unable to install handler , display message to userprintf ( "Unable to install handler!\n" );return -1 ;

}第一个参数是函数指针,就是上面的那个函数。第二个参数是标志,如果为 TRUE 那么就安装钩子,如果为 FALSE 那么删除钩子。在安装了钩子后,我们就能收到控制台消息了,在程序退出前,要删除钩子。

应用程序

93

signal 和 raise

signal 设置中断信号处理例程; Raise 用于发送信号; 6种信号与传统 UNIX 系统相同,而控制台信号仅 Windo

ws 2000/xp 特有

信号名 说明SIGABRT 非正常终止SIGFPE 浮点计算错误SIGFPE 非法指令SIGINT CTRL+C 信号 ( 对 Win32 无效 )SIGSEGV 非法存储访问SIGTERM 终止请求

http://www.acm.uiuc.edu/webmonkeys/book/c_guide/2.9.html

#include<signal.h> #include<stdio.h> void catch_function(int);int main(void) { if(signal(SIGINT, catch_function)==SIG_ERR){ printf("error when setting a signal handler.\n");

exit(0); }

printf("Raising the interactive attention signal.\n"); if(raise(SIGINT)!=0){

printf("Error raising the signal.\n"); exit(0); } printf("Exiting.\n"); return 0; } void catch_function(int signal) { printf("Interactive attention signal caught.\n"); }

signalraise

95

Windows 2000/XP 基于文件映射的共享存储区

用于进程间大容量通信,通信各进程可任意读写存储区,需要同不遇互斥来保证一致性

Windows2000/xp采用文件映射机制实现共享存储区 将整个文件映射为进程虚拟地址空间的一部分来加以访问

CreateFileMapping 为指定文件创建一个文件映射对象,返回对象指针;

OpenFileMapping打开一个命名的文件映射对象,返回对象指针; MapViewOfFile 把文件映射到本进程的地址空间,返回映射地址

空间的首地址; FlushViewOfFile 可把映射地址空间的内容写到物理文件中; UnmapViewOfFile 拆除文件映射与本进程地址空间间映射关系; CloseHandle 关闭文件映射对象;

96

Windows 2000/XP 管道 一条在进程间以字节流方式传输的通信信道 利用操作系统核心的缓冲区实现的单项通信 常用于命令行指定的输入输出重定向和管道命令 Windows 2000/XP提供无名管道和命名管道两种

管道机制。 Windows 2000/XP 的无名管道类似于 UNIX 系统

的管道,但更完善。 利用 CreatePipe 创建无名管道,并得到读写句柄; 然后利用 ReadFile 和 WriteFile 可对无名管道进行读写。

97

命名管道 服务器进程与一个客户进程间的通信通道;可实现不同

机器上的进程通信;支持多客户; 基于客户服务器模式连接本机或网络中的两个进程; 管道名字:

作为服务器方创建命名管道时,只能以 \\.\pipe\PipeName 形式命名,不能在其它机器上创建管道;

作为客户方连接到一个命名管道实例的一方时,可以是 \\serverName\pipe\pipename ;

第一部分 \\Server 指定了服务器的名字,命名管道服务即在此服务器创建,其字串部分可表示为一个小数点(表示本机)、星号(当前网络字段)、域名或是一个真正的服务;第二部分 \Pipe 与邮槽的 \Mailslot 一样是一个不可变化的硬编码字串,以指出该文件是从属于 NPFS(Named Pipe File System);第三部分 \[Path]Name则使应用程序可以唯一定义及标识一个命名管道的名字,而且可以设置多级目录。

98

创建命名管道 CreateNamedPipe在服务器端创建并返回一个命名

管道句柄; ConnectNamedPipe在服务器端等待客户进程的请

求; CallNamedPipe 从管道客户进程建立与服务器的管道连接;

ReadFile 、 WriteFile(用于阻塞方式)、 ReadFileEx 、 WriteFileEx(用于非阻塞方式)用于命名管道的读写;

HANDLE CreateNamedPipe(  LPCTSTR lpName, // 指向管道名称的指针  DWORD dwOpenMode, // 管道打开模式  DWORD dwPipeMode, // 管道模式  DWORD nMaxInstances, // 最大实例数  DWORD nOutBufferSize, // 输出缓存大小  DWORD nInBufferSize, // 输入缓存大小  DWORD nDefaultTimeOut, // 超时设置  LPSECURITY_ATTRIBUTES lpSecurityAttributes // 安全属性指针);

命名管道服务器sprintf(pipenamestr,"\\\\.\\pipe\\pipename");SvrHandle=CreateNamedPipe(pipenamestr, PIPE_ACCESS_DUPLEX|FILE_FLAG_WRITE_THROUGH, // 阻塞模式,这种模式仅对“字节传输管道”操作有效 PIPE_READMODE_BYTE | PIPE_TYPE_BYTE, // 字节模式 PIPE_UNLIMITED_INSTANCES, 128,128, NULL,NULL); if(SvrHandle==INVALID_HANDLE_VALUE) AfxMessageBox(“管道创建失败!” ); else{ AfxMessageBox(“建立管道成功!” ); if(ConnectNamedPipe(SvrHandle,NULL)==FALSE){ AfxMessageBox(" 建立连接失败! "); }else{ AfxMessageBox(“建立连接成功!” ); ReadFile(SvrHandle, buffer, sizeof(buffer), &ReadNum, NULL); buffer[strlen(buffer)] = '\0'; printf("recv: %s\n", buffer); } if (DisconnectNamedPipe(SvrHandle)==FALSE) // 终止连接 AfxMessageBox(“终止连接失败 !”); else{ CloseHandle(SvrHandle); // 关闭管道句柄 AfxMessageBox(“成功终止连接 !”); }}

sprintf(pipenamestr,"\\\\.\\pipe\\pipename");if(WaitNamedPipe(pipenamestr, NMPWAIT_WAIT_FOREVER)==FALSE) // 管道名要遵循UNC ,格式为 \ \ . \pipe\pipname, 名字不分大小写 AfxMessageBox(" 操作失败,请确定服务端正确建立管道实例! ");else{ CltHandle=CreateFile(pipenamestr, GENERIC_READ|GENERIC_WRITE,

FILE_SHARE_READ| FILE_SHARE_WRITE,NULL, OPEN_EXISTING, // 为了与命名管道连接,此参数应一直为 OPEN_EXISTINGFILE_ATTRIBUTE_ARCHIVE|FILE_FLAG_WRITE_THROUGH,

// FILE_FLAG_WRITE_THROUGH会使管道WriteFile 调用处于阻塞状态,

//直到数据传送成功。NULL);

printf("...\n");

命名管道客户端

if(CltHandle== INVALID_HANDLE_VALUE) AfxMessageBox(" 管道连接失败 ");else{ // 向管道写入数据 if(WriteFile(CltHandle, Message, Message.GetLength(), &WriteNum, NULL) == FALSE){

AfxMessageBox(“数据写入管道失败 !”); // 显示信息 } else { printf("send ok!\n"); ReadFile(CltHandle, buffer, sizeof(buffer), &ReadNum, NULL); buffer[ReadNum] = '\0'; printf("recv: %s\n", buffer); AfxMessageBox(" 数据成功写入管道 !"); // 显示信息 } CloseHandle(CltHandle); // 关闭管道句柄 } } }scanf("%d", &WriteNum);return nRetCode;

管道客户

管道服务器

102

Windows 2000/XP 邮件槽 (mailslot) 邮件槽:不定长数据块(报文),不可靠传递 消息发送不需接收方准备好,随时可以发送 采用客户服务器模式:单向,只能从客户端发到服务器端; server 负责创建邮件槽,可从邮件槽中读消息; client 可利用邮件槽的名字向它发送消息;

邮件槽名字: 客户方(发送方)可打开其他机器上的邮件槽,命名方式可为“ \

\range\mailslot\[path]name”,这里 range 可以是 本机、其他机器的名字或域名;

服务器(接收方)只能在本机建立邮件槽,名字可为 "\\.\mailslot\[path]name" ;

在邮件槽的所有服务器句柄关闭后,邮件槽被关闭。这时,未读出的报文被丢弃,所有客户句柄都被关闭

103

CreateMailslot 服务器方创建邮件槽,返回其句柄; GetMailslotInfo 服务器查询邮件槽的信息,如:消息长度、消息数目、读操作等待时限等;

SetMailslotInfo 服务器设置读操作等待时限; ReadFile 服务器读邮件槽; CreateFile 客户方打开邮件槽; WriteFile 客户方发送消息;

104

套接字 网络上不同主机间进行双向通信的通信机制 数据格式为可靠的字节流(面向连接)或报文(非连接);主要用于网络通信;

为实现不同 OS 上的进程通信,需约定通信时不同层次的通信过程和消息格式,既需要协议;

UNIX 中使用的 BSD 套接字主要基于 TCP/IP ,提供 send ,sendto , recv, recvfrom等函数

在Windows 2000/XP 中的规范称为“Winsock“,函数扩展为 WSASend , WSASendto , WSARecv, WSARecvfrom。

winsock程序

105

实验二 编写基于邮件槽的进程,实现通信 采用 winsock编写客户、服务器程序,实现网络通信

106

107

108

3.6 死锁问题 指系统中多个进程无限制地等待永远不会发生的条件 根本原因:对互斥资源的共享、并发执行进程间的同步关

系不当 可重用资源:每时只有一进程使用,宏观上轮流使用,如

处理器、 I/0 等 使用顺序导致死锁 可消耗资源:动态生成、消耗的资源,不限制数量,如中

断、信号、消息等 互等对方生成资源导致死锁

109

死锁发生的条件 互斥:任意时刻只允许一个进程使用资源 请求和保持:进程在请求其余资源时,不主动放弃已经

占用的资源 非剥夺:进程已经占用的资源,不会被强制剥夺 环路等待:环路的每一条边是进程在请求另一进程已经

占用的资源

表 3-5 三种方法处理死锁问题

110

死锁的预防 通过某种策略来限制并发进程对资源的请求,使系统在任何时刻

都不满足死锁的必要条件; 预先静态分配法, 条件 2 限制并发程度 有序资源使用法, 条件 4 限制进程对资源的申请顺序

死锁的检测 操作系统中保存资源的请求和分配信息,利用某种算法对这些信

息加以检查,判断是否存在死锁 主要检查是否有循环 解除死锁,造成进程终止和重新启动, 选择代价较小的

死锁的避免 分配资源时判断是否会死锁,确信不死锁时才分配 银行家算法

111

3.7 处理器调度 让哪个任务,在什么条件下,什么时候启动的问

自学

112

3.8 调度算法 先来先服务 FCFS (宏观)

简单,按照进程到达的先后顺序, 非枪占式 有利于长作业,不利于短作业(队后短作业长时间等待);有利

于处理器繁忙的作业,不利于 I/O忙的作业; 最短作业优先 SJF (最短进程优先) (宏观)

目标:改进 FCFS ,减少进程平均周转时间 改善了平均周转时间;提高吞吐量 不利于短作业;无优先级;难以准确估计作业的执行时间 最短剩余时间优先( SRT)、最高响应比优先( HRRN)

时间片时钟算法 按 FCFS 排队,每个进程执行 n 毫秒

多极队列算法 多个就绪队列 优先级算法

改进的多级队列调度算法 静态优先级、动态优先级

113

3.9 Windows 2000/XP 的线程调度 Windows 2000/XP 的处理器调度的调度对象:线

程线程调度 线程调度并不单纯使用某一种调度算法,而是多种算法的综合,针对实际系统的需要进行优化和改进

114

Windows 2000/XP 的线程调度特征

基于优先级的抢先式多处理器调度系统 调度系统总是运行优先级最高的就绪线程 线程进入运行状态,可运行一个时间配额的时间

片,用完时间配额线程运行将被中断 线程调度的触发事件

一个线程进入就绪状态 线程时间配额用完,从运行状态转到退出、等待状态 线程优先级改变 正在运行的线程改变了其亲和处理器

115

线程调度相关的编程接口 Suspend/ResumeThread 挂起 /激活 Get/SetPriorityClass 设置 /读取进程的基本优先级 Get/SetThreadPriority 读取 /设置线程的相对优先级 Get/SetProcessAffinityMask 读取 /设置进程的亲和处理器集合 SetThreadAffinityMask 设置线程的亲和处理器集合 Get/SetProcessPriorityBoost 读取 /设置系统暂时提升线程优先级

状态 SetThreadIdealProcessor设置线程首选处理器 Get/SetThreadPriorityBoost SwitchToThread Sleep SleepEx

116

线程优先级 32 个,分为三部分 16 个实时线程优先级 15 个可变线程优先级 1 个系统线程优先级 零页线程

两种方法制定线程优先级 用户编程接口 Windows 2000/xp 操作系统内核可控制线程的优先级

117

实时优先级 应用程序中,要把线程的优先级提升到实时优先级,用

户必须有升高线程优先级的权限;否则只能提升到高级优先级;

如果用户进程在实时优先级运行时间过多,它将可能阻塞关键系统功能的执行,阻塞系统线程的运行;但由于中断优先级比任何线程都高,不会阻塞硬件中断处理。

在被其他线程抢先时,具有实时优先级线程与具有可变优先级线程的行为是不同的。

Windows 2000/XP 并不是通常意义上的实时,并不提供实时操作系统服务。

118

线程时间配额 一个线程进入运行状态到系统检查是否有其他优先级相

同的线程需要开始运行之间的时间总和; 线程用完了自己的时间配额时,如没有其它相同优先级

线程, Windows 2000/XP 将重新给该线程分配一个新的时间配额,并继续运行。

时间配额不是一个时间长度值,而一个称为配额单位(quantum unit) 的整数。

119

时间配额的计算 缺省时,在Windows 2000 专业版中线程时间配额为 6 ;而在Wi

ndows 2000 服务器中线程时间配额为 36。 在Windows 2000 服务器中取较长缺省时间配额的原因是,保证客户请求所唤醒的服务器应用有足够的时间在它的时间配额用完前完成客户的请求并回到等待状态。

每次时钟中断,时钟中断服务例程从线程的时间配额中减少一个固定值 (3)。

如果没有剩余的时间配额,系统将触发时间配额用完处理,选择另外一个线程进入运行状态。

在Windows 2000 专业版中,由于每个时钟中断时减少的时间配额为 3 ,一个线程的缺省运行时间为 2 个时钟中断间隔;在Windows 2000 服务器中,一个线程的缺省运行时间为 12 个时钟中断间隔。

120

不同硬件平台的时钟中断间隔是不同的,时钟中断的频率是由硬件抽象层确定的,而不是内核确定的。

大多数 x86 单处理机系统的时钟中断间隔为 10 毫秒

大多数 x86多处理机系统的时钟中断间隔为 15 毫秒

121

时间配额的控制 在系统注册库中的一个注册项“ HKLM\SYSTEM\Curre

ntControlSet\Control\PriorityControl\Win32PrioritySeparation”,允许用户指定线程时间配额的相对长度和前台进程的进程的时间配额是否加长。该注册项为6位,分成 3 个字段,每个字段占 2位。

时间配额长度 前后台变化 前台进程时间配额提升

024

122

时间配额长度字段 (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。

123

提高前台线程优先级 假设用户首先启动了一个运行时间很长的电子表格计算程序,然

后切换到一个计算密集型的应用 (如一个需要复杂图形显示的游戏 )。

如果前台的游戏进程提高它的优先级,后台的电子表格将会几乎得不到 CPU时间。

但增加游戏进程的时间配额,则不会停止电子表格计算的执行,只是给游戏进程的 CPU时间多一些。

如果用户希望运行一个交互式应用程序时的优先级比其他交互进程的优先级高,可利用任务管理器来修改进程的优先级类型为中上或高级,也可利用命令行在启动应用时使用命令“ start /abovenormal”或“ start /high”来设置进程优先级类型。

124

调度数据结构 调度策略

主动切换 进入等待状态,放弃处理器使用 抢先 时间配额用完 结束

线程优先级的提升 目的是提高系统吞吐量,相应时间等特征

125

实验三 在进程中创建多个线程并观察线程的运行顺序 提升线程的优先级,再观察线程的运行状态 结合线程技术和 winsock技术改进实验二中的服务器程序,使其支持多客户,但客户不多于 256