软考-软件设计师中级备考 8、进程管理
操作系统作为系统硬件资源和软件资源的管理者,向上层提供方便易用的服务,如操作系统的图形用户界面(GUI),是硬件层之上的第一层软件 如显卡驱动。特征是:并发、共享、虚拟、异步。
硬件资源(存储管理、设备管理) 软件资源(进程管理、文件管理)
一、状态转换图
进程通常具备五种基本状态:创建态、就绪态、运行态、阻塞态和终止态。状态转换图以可视化方式,精准呈现进程在这些状态之间的转换逻辑与关系。
1.1 创建态到就绪态
当操作系统着手创建新进程时,会依次执行资源分配、初始化进程控制块(PCB)等操作。以在 Windows 系统中启动大型游戏《英雄联盟》为例,系统首先会为该游戏进程分配初始内存空间,用于加载游戏的基础程序代码与配置数据;接着构建 PCB,在其中记录进程的优先级、初始状态等关键信息。当这些核心操作完成后,游戏进程便从创建态顺利过渡到就绪态,进入就绪队列等待 CPU 调度执行。
1.2 就绪态到运行态
调度程序依据特定算法,从就绪队列中挑选进程投入运行。假设系统处于多任务繁忙状态,就绪队列中有浏览器进程(用于浏览网页)、音乐播放器进程(播放背景音乐)、游戏进程(运行《英雄联盟》)。若采用优先级调度算法,且游戏进程被赋予较高优先级,那么调度程序会选中游戏进程,使其从就绪态切换为运行态,进而占用 CPU 资源,执行游戏的各项指令,如渲染游戏画面、处理玩家操作输入等。
1.3 运行态到阻塞态
当进程遭遇需等待外部事件完成的情况时,会主动进入阻塞态。继续以《英雄联盟》游戏进程为例,在游戏运行过程中,若需要从硬盘加载新的游戏地图数据,由于硬盘 I/O 操作速度远低于 CPU 处理速度,在等待数据读取完成的时间段内,游戏进程会进入阻塞态。此时,CPU 资源会被释放,调度程序将其分配给其他就绪态进程,如音乐播放器进程可继续播放音乐。
1.4 阻塞态到就绪态
一旦进程所等待的事件完成,便会立即从阻塞态转换为就绪态。在上述游戏加载地图数据的场景中,当硬盘成功将地图数据传输至内存后,游戏进程所等待的 I/O 事件结束,它会迅速从阻塞态切换为就绪态,重新进入就绪队列,等待 CPU 再次调度,以便继续执行后续的游戏逻辑,如显示新地图画面、加载 NPC 信息等。
1.5 运行态到就绪态
存在两种常见情况会促使进程从运行态转变为就绪态。其一,若采用时间片轮转调度算法,当进程分配到的时间片耗尽时,即便任务尚未完成,也会被暂停执行,转换为就绪态。例如,音乐播放器进程在时间片内仅完成了部分歌曲解码操作,时间片用完后,它会被暂停,进入就绪队列等待下一轮调度。其二,当有更高优先级的进程进入就绪队列时,当前运行的低优先级进程也会被切换为就绪态。比如,系统突然出现一个紧急的系统更新进程(优先级极高),正在运行的音乐播放器进程会立即被中断,转为就绪态,让位于系统更新进程。
1.6 运行态到终止态
进程完成预定任务或遭遇异常错误时,会进入终止态。以音乐播放器进程为例,若其正常播放完所有歌曲列表中的曲目,任务圆满完成,便会进入终止态,操作系统随后回收其占用的内存、音频设备等资源;若在播放过程中,因软件代码出现严重逻辑错误导致程序崩溃,同样会进入终止态,操作系统同样会进行资源回收操作,以释放系统资源供其他进程使用。
1.7 就绪态到终止态
在一些特殊情形下,就绪态进程会直接进入终止态。例如,系统管理员在任务管理器中手动强制关闭一个处于就绪态的应用程序进程(如一个未响应的图像编辑软件进程);或者系统资源严重不足,无法满足就绪队列中某些进程的资源需求,系统会强制终止部分就绪态进程,以保障关键系统进程的正常运行,此时被终止的就绪态进程便直接进入终止态。
二、前驱图
前驱图作为有向无环图,能清晰界定进程间的先后执行顺序。图中的节点代表进程,有向边明确表示进程间的前驱关系。例如,在一个视频渲染项目中,存在三个进程:P1 负责视频素材导入,P2 负责特效添加,P3 负责最终视频导出。由于必须先导入素材,才能添加特效,最后导出视频,所以存在有向边 P1→P2 和 P2→P3。这意味着进程 P2 必须在 P1 执行完毕后才能启动,P3 则需在 P2 完成后执行,通过前驱图可直观规划和管理这些进程的执行流程,避免因执行顺序错误导致的任务失败。
三、进程同步机制
进程同步旨在确保多个进程在执行顺序上相互协调,保障程序执行的正确性与结果一致性。
3.1 信号量同步
以生产者 - 消费者模型为例,生产者进程负责生产数据并放入缓冲区,消费者进程从缓冲区读取数据。设置两个信号量:empty(表示缓冲区空闲槽位数量,初始值为缓冲区大小)和 full(表示缓冲区中已填充数据的槽位数量,初始值为 0)。生产者进程在生产数据前执行 P (empty),若缓冲区已满,empty 值减为负数,生产者进程阻塞;生产数据后执行 V (full),唤醒可能阻塞的消费者进程。消费者进程在读取数据前执行 P (full),若缓冲区为空,full 值减为负数,消费者进程阻塞;读取数据后执行 V (empty),唤醒可能阻塞的生产者进程,以此实现两者的同步执行。
3.2 管程同步
管程是一种编程语言结构,封装了共享数据及对其操作的过程。在多线程文件读写场景中,可定义一个管程类,其中包含文件句柄、读写锁等数据成员,以及打开文件、读取数据、写入数据等操作过程。多个线程若要访问文件,必须通过调用管程类的相关过程,管程内部通过锁机制确保同一时刻仅有一个线程能执行文件读写操作,从而实现线程间的同步,避免文件数据的读写冲突。
3.3 消息传递同步
在分布式系统中,不同节点上的进程可通过消息传递实现同步。例如,节点 A 上的进程 P1 需要节点 B 上的进程 P2 处理完数据后返回结果,P1 会向 P2 发送包含任务请求的消息。P2 收到消息后开始处理数据,处理完成后向 P1 回传包含结果的消息。P1 在发送请求消息后,可选择阻塞等待 P2 的回复消息,也可继续执行其他任务,待收到 P2 的消息后再根据结果进行后续操作,通过这种消息交互实现进程间的同步协调。
四、进程互斥机制
进程互斥确保多个进程对临界资源的访问相互排斥,避免数据不一致问题。
4.1 Peterson 算法(软件实现)
假设有两个进程 P0 和 P1 竞争访问临界区。算法通过设置两个标志位 flag [0] 和 flag [1],分别表示进程 P0 和 P1 是否准备进入临界区,以及一个变量 turn,用于记录轮到哪个进程进入临界区。在进入临界区前,进程先设置自己的标志位为真,并将 turn 设置为对方进程编号,然后检查对方标志位和 turn 的值。若对方不想进入临界区,或者轮到自己进入临界区,则可进入临界区;否则等待。例如,P0 想要进入临界区,先设置 flag [0]=true,turn=1,然后检查发现 flag [1]=false(即 P1 不想进入),则 P0 可顺利进入临界区,在退出临界区时将 flag [0] 设为 false,确保其他进程有机会进入,以此实现软件层面的进程互斥。
4.2 TestAndSet 指令(硬件实现)
TestAndSet 指令是硬件提供的原子操作。假设有一个共享的锁变量 lock,初始值为 0。进程尝试进入临界区时,执行 TestAndSet (lock) 指令,该指令会返回 lock 的旧值,并将 lock 设为 1。若返回值为 0,说明没有其他进程占用临界区,当前进程可进入;若返回值为 1,则表示已有进程在临界区,当前进程需等待。例如,进程 P1 执行 TestAndSet (lock),返回 0,lock 变为 1,P1 进入临界区;此时进程 P2 执行 TestAndSet (lock),返回 1,P2 需等待 P1 退出临界区并将 lock 重新设为 0 后,才能尝试进入,通过硬件指令实现高效的进程互斥。
4.3 基于信号量的互斥
使用二进制信号量可轻松实现进程互斥。将二进制信号量 mutex 初始化为 1,多个进程在进入临界区前执行 P (mutex) 操作,若 mutex 值减为 0,说明成功获取锁,可进入临界区;若 mutex 值变为负数,进程阻塞。在退出临界区时执行 V (mutex) 操作,唤醒可能阻塞的其他进程。例如,多个进程同时访问共享的打印机资源,每个进程在使用打印机前执行 P (mutex),确保同一时刻仅有一个进程能占用打印机,使用完毕后执行 V (mutex),让其他进程有机会使用,有效避免打印机资源的冲突使用。
五、信号量机制
信号量是控制进程对共享资源访问的核心工具,分为二进制信号量和计数信号量。
5.1 二进制信号量
其取值固定为 0 或 1,常用于实现进程互斥。以多个进程访问共享文件为例,设置二进制信号量 file_lock 初始值为 1。进程在读取或写入文件前,先执行 P (file_lock),若成功获取(file_lock 变为 0),则可对文件进行操作;操作完成后执行 V (file_lock),释放文件锁,允许其他进程访问。若有多个进程同时尝试访问文件,只有一个进程能成功执行 P (file_lock),其他进程将被阻塞,直至锁被释放,从而保证文件资源的互斥访问。
5.2 计数信号量
其取值为非负整数,可用于进程同步与资源计数。例如,系统中有 3 台打印机可供多个进程使用,设置计数信号量 printer_count 初始值为 3。进程需要使用打印机时,执行 P (printer_count),若 printer_count 值大于 0,说明有可用打印机,值减 1 后进程可使用打印机;若 printer_count 值变为 0,说明打印机已全部被占用,进程阻塞等待。当进程使用完打印机后,执行 V (printer_count),释放一台打印机资源,若有进程阻塞等待,会唤醒其中一个进程继续执行,通过计数信号量有效管理打印机资源的分配与使用。
六、PV 操作
PV 操作是对信号量进行操作的原语。
6.1 P 操作
P 操作(wait 操作)用于申请资源。以停车场车辆进出管理为例,假设停车场最多容纳 10 辆车,设置计数信号量 parking_space 初始值为 10。每辆车进入停车场时,执行 P (parking_space),若此时停车场还有空位(parking_space 值大于 0),值减 1 后车辆可进入;若停车场已满(parking_space 值为 0),后续执行 P 操作的车辆进程将被阻塞,等待其他车辆离开停车场释放资源。
6.2 V 操作
V 操作(signal 操作)用于释放资源。在上述停车场场景中,当车辆离开停车场时,执行 V (parking_space),将 parking_space 值加 1,若有其他车辆进程因等待停车位而阻塞,会唤醒其中一个进程,允许其进入停车场,通过 PV 操作实现对停车场资源的动态管理与控制。
七、PV 操作实现前驱操作 刷题
通过设置信号量可精准实现进程间的前驱关系。例如,在一个视频编辑项目中,有三个进程:P1 负责视频剪辑,P2 负责添加字幕,P3 负责生成最终视频。要求 P2 在 P1 完成后执行,P3 在 P2 完成后执行。设置三个信号量 S1、S2、S3,初始值均为 0。在 P1 剪辑视频完成后执行 V (S1);P2 在开始添加字幕前执行 P (S1),若 P1 未完成,P2 将阻塞等待;P2 添加字幕完成后执行 V (S2);P3 在生成最终视频前执行 P (S2),若 P2 未完成,P3 将阻塞等待。以此类推,通过 PV 操作确保进程按 P1→P2→P3 的顺序依次执行,保障视频编辑任务的正确流程。
八、死锁
死锁是多个进程因争夺资源陷入的僵局。
8.1 死锁的四个必要条件
- 互斥条件:资源在某一时刻只能被一个进程占用。例如,打印机在打印文件时,其他进程无法同时使用,满足互斥条件。
- 请求和保持条件:进程已持有资源,同时又请求其他资源且不释放已持有的资源。如进程 P1 已占用一台扫描仪,又请求使用一台打印机,且不释放扫描仪,符合该条件。
- 不可剥夺条件:资源只能由持有它的进程主动释放,其他进程无法强行剥夺。例如,进程 P2 占用的内存空间,其他进程不能直接抢夺,满足不可剥夺条件。
- 环路等待条件:多个进程形成一个资源请求环路,每个进程都在等待下一个进程释放资源。例如,进程 P3 等待 P4 释放 CPU 资源,P4 等待 P3 释放内存资源,形成环路等待,四个条件同时满足时便会产生死锁。
九、死锁的处理策略
9.1 预防死锁
通过破坏死锁必要条件实现。例如,采用资源静态分配策略,进程在启动时一次性申请所需的全部资源,避免运行中请求其他资源,从而破坏请求和保持条件;采用可剥夺资源分配策略,当高优先级进程需要资源时,可从低优先级进程手中剥夺资源,破坏不可剥夺条件,以此预防死锁发生。
9.2 避免死锁
银行家算法是典型的避免死锁算法。假设系统中有 3 个进程 P1、P2、P3,2 类资源 R1、R2,系统拥有 R1 资源 9 个,R2 资源 8 个。记录每个进程的最大资源需求、已分配资源量、剩余资源量。当 P1 请求 2 个 R1 和 1 个 R2 时,系统先检查请求是否合理(未超过最大需求且系统有足够资源),然后尝试分配,接着检查系统是否处于安全状态(是否存在一种分配顺序使所有进程都能完成)。若分配后系统安全,则实际分配资源;否则拒绝请求,通过动态监测和合理分配资源,避免系统进入不安全状态,从而防止死锁。
9.3 检测死锁
定期检查系统资源分配图,判断是否存在环路。若存在环路且环路上每个进程已占用的资源数都小于其所需资源数,则检测到死锁。例如,通过资源分配图发现进程 P4、P5、P6 形成资源请求环路,且各自持有的资源无法满足需求,确定发生死锁。
9.4 解除死锁
可采用资源剥夺法,从死锁进程中剥夺部分资源分配给其他进程,打破死锁环路;或采用撤销进程法,强制终止一个或多个死锁进程,释放其占用资源,使系统恢复正常运行,解决死锁问题。