(进程控制)
导读大家好,很高兴又和大家见面啦!!!
在上一篇内容中,我们共同探讨了进程控制的基本概念与实现原理:
进程控制是操作系统对进程实施有效管理的核心功能,它通过特定的机制实现进程的创建、终止以及各种状态间的转换,从而确保多进程能够高效并发执行。我们重点学习了实现进程控制的关键工具——原语:
原语是由若干指令组成的、用于完成特定功能的过程,具有不可分割性,即执行必须是连续的,在执行过程中不允许被中断。这种"原子操作"特性是确保进程状态转换一致性和可靠性的基础。
还记得我们讨论过的关键问题吗?——为什么进程控制必须通过原语来实现?
正是因为进程状态的转换涉及多个步骤
修改状态标志将进程PCB插入相应队列\cdots如果这些操作在执行过程中被中断,就可能导致进程状态不一致,进而引发系统错误。
原语通过关中断和开中断这两条特权指令,确保了一系列操作的原子性,从而避免了此类问题。
理解了进程控制的"为什么"和"如何实现"之后,我们现在很自然会问:
操作系统具体是如何运用不同的原语来管理进程的完整生命周期的?各种原语的执行细节和应用场景又是怎样的?现在,就让我们带着这些问题,一起深入探讨进程创建、终止、阻塞与唤醒、切换这四类核心原语的具体实现机制,揭开操作系统精准控制进程生命周期的神秘面纱。
一、进程的创建1.1 创建原语创建原语指的是操作系统创建一个进程时使用的原语。
操作系统在创建一个新的进程时,会执行以下操作:
为新进程分配一个唯一的进程标识号(PID),并申请一个空白 PCB。 由于 PCB 是有限的,因此在创建的过程中可能会因为 PCB 申请失败而导致进程创建失败为进程分配其运行所需的资源,如内存、文件、I/O 设备 和 CPU 时间等。 这些资源可以从操作系统中获取,也可以从其父进程中获取。若资源不足(如内存),并不会导致进程创建失败,而是使该正在创建的进程进入创建态,等待分配所缺失的资源初始化 PCB。 该过程主要包括初始化以下信息: 标志信息CPU 状态信息CPU 控制信息设置进程的优先级等将 PCB 插入到就绪队列。 若就绪队列能够容纳新进程,则将新进程插入就绪队列,等待被调度运行若就绪队列无法容纳新进程,该进程会被挂起就绪队列的容量是有限的,以下原因均会导致就绪队列无法容纳新进程: 系统负载过高:同时运行的进程过多,耗尽了内存资源。内存不足:物理内存有限,无法为更多进程提供运行空间。负荷调节:操作系统为了确保系统整体性能,主动挂起一些不重要的进程。1.2 创建进程的操作在操作系统中,当执行以下操作时,均会创建一个新的进程:
终端用户登录系统 在分时操作系统中,用户登录成功时,系统会为其建立一个新的进程作业调度 多道批处理系统中,有新的作业放入内存是,会为其建立一个新的进程作业指的是存在于外存中,还未投入到运行中的应用程序系统提供服务 用户向操作系统提出某些请求时,会建立一个进程处理该请求用户程序的应用请求 由用户进程主动请求创建一个子进程在操作系统中,允许一个进程创建另一个进程,此时创建者为父进程,被创建的进程为子进程。子进程可以继承父进程所拥有的资源。当子进程终止时,应将其从父进程那里获得的资源还给父进程二、进程的终止2.1 撤销原语撤销原语又称为终止原语,是操作系统在终止一个进程时使用的原语。
操作系统在终止一个进程时,会执行以下操作:
根据被终止进程的 PID ,检索出该进程的 PCB,从中读取该进程的状态 若被终止的进程处于运行态,立即终止该进程的执行,剥夺该进程的 CPU 资源,并将 CPU 资源分配给其他进程若该进程还有子孙进程,则通常需要将其所有子孙进程终止(有些系统无该要求)将该进程所拥有的全部资源归还给操作系统或者父进程。将该 PCB 从所在队列中删除 有些操作系统不允许子进程在父进程终止的情况下存在,对于这类系统,若一个进程终止,则它的所有子进程也终止,这种现象称为级联终止。 当然,并不是所有操作系统都是这样设计的。
2.2 终止进程的操作在操作系统中,当发生以下事件时,均会引起进程的终止:
正常结束。
当该进程的任务已经完成并准备退出运行 异常结束。 进程在运行时,发生了某种异常事件,使程序无法继续运行。这里我们例举几个典型的异常事件: 存储区越界:比如数组的越界访问、栈溢出等 保护错:是操作系统和处理器硬件共同构建的一套保护机制,当进程试图执行以下操作时,就会触发保护错: 内存访问违规:试图读写不属于自己的内存地址,或访问一个尚未映射物理内存的地址(例如空指针解引用)。 非法指令:试图执行一条为操作系统保留的特权指令(如直接进行I/O操作),而进程自身没有此权限。 资源访问违规:以不当方式访问资源,例如尝试写入一个只读文件。 运行超时:当存在超时设置不合理、 程序逻辑缺陷算(如死循环)、算法的时间复杂度过高(如使用 O(N^3) 的算法处理大规模的数据)、存在冗余计算、资源不足(CPU、内存)、网络延迟或外部依赖、低效I/O操作、数据结构选择不当(如采用顺序表进行频繁的插入与删除) 算术运算错:常见的算术错误有以下几种 除零错误:这是最常见的算术异常之一。在整数运算中,除数是绝对不允许为0的,否则程序会抛出异常(如 Java 中的 ArithmeticException 或 Python 中的 ZeroDivisionError)。 整数溢出:当算术运算的结果超出了该数据类型所能表示的范围时就会发生。 浮点数特殊值:浮点数运算在特定情况下(如非零数除以零)可能得到 Infinity(无穷大),而对负数开平方等无效操作会得到 NaN(Not a Number)。 I/O 故障:当计算机试图与外部世界(比如硬盘、U盘、打印机、网络等)交换数据时,这个过程因某种原因失败了。 外界干预。进程应外界的请求而终止运行。 在 Windows 系统中,用户可以通过快捷键 Ctrl + Alt + Delete 打开任务管理器来主动的终止进程 三、进程的阻塞与唤醒3.1 阻塞原语阻塞原语是指进程由运行态转换为阻塞态时使用的原语。
阻塞原语在执行的过程中,会进行以下操作:
找到将要被阻塞进程的标识号(PID)对应的 PCB若该进程为运行态,则保护其线程,将其状态转为阻塞态,停止运行将该 PCB 插入相应事件的等待队列,将 CPU 资源调度给其他就绪进程3.2 阻塞进程的操作正在执行的进程,由于期待的某些事件未发生:
请求系统资源失败等待某种操作的完成新数据尚未到达无新任务可做等,进程便通过调用阻塞原语(Block),使自己由运行态变为阻塞态。
阻塞是进程自身的一种主动行为,也因此只有处于运行态的进程,才可能将其转为阻塞态。
3.3 唤醒原语唤醒原语是指进程由阻塞态转换为就绪态时使用的原语。
唤醒原语在执行的过程中会执行以下操作:
在该事件的等待队列中找到相应进程的 PCB将其从等待队列中移除,并置其状态为就绪态将该 PCB 插入到就绪队列中,等待调度程序调度3.4 唤醒进程的操作当被阻塞进程所期待的事件发生时,如:
所请求的系统资源获取成功所期待的 I/O 操作已经完成所期待的数据已经到达获取到新的任务由有关进程(如释放系统资源的进程、提供数据的进程、发布任务的进程)调用唤醒原语(Wakeup),将等待该事件的进程唤醒。
3.5 阻塞与唤醒Block 原语和 Wakeup 原语是一对作用刚好相反的原语,必须成对使用。
若在某个进程中调用了 Block 原语,则必须在与之合作的或其他相关的进程中安排一条相应的 Wakeup 原语,以便唤醒阻塞进程;否则,阻塞进程将因不能被唤醒而永久地处于阻塞态。
四、进程的切换4.1 切换原语切换原语是指实现进程从运行态转换为就绪态并将新进程从就绪态转换为运行态的原语。
切换原语在使用时,会执行以下操作:
将运行环境信息存入 PCBPCB 移入相应队列选择另一个进程执行,并更新其 PCB根据 PCB 恢复新进程所需的运行环境4.2 切换进程的操作在操作系统中,当出现以下事件时,会通过调用 切换原语 来进行进程的切换:
当前进程的 CPU 时间片已经结束有更高优先级的进程到达当前进程主动阻塞当前进程终止简单的理解就是,当前正在运行的进程因为各种原因需要结束运行态并转换为其它状态时,就需要通过调用切换原语来进行进程的状态切换,并将 CPU 资源分配给新的进程;
4.3 程序的运行过程从程序的创建到运行的过程中,会经历以下步骤:
程序源代码的编写源程序通过编译、链接等操作生成可执行文件.exe并存储与硬盘中将位于硬盘的 .exe 文件放入到内存中CPU 从内存中依次读取程序指令代码语言:javascript复制graph LR
a[源文件]
subgraph 硬盘
b[可执行文件]
end
a--->b
subgraph 内存
PCB
c1[指令1]
c2[指令2]
c3[...]
end
b--->c1
c1--->CPU程序在放入内存中运行时,会创建一个 PCB 用于存储该进程的管理和控制信息。
但是由于 CPU 的调度是以时间片的形式,且对应的时间片只有若干毫秒。
因此当一个进程对应的 CPU 时间片使用完后,系统会通过 切换原语 将该进程切换为另一个新进程:
代码语言:javascript复制graph LR
subgraph A[内存]
PCB1
a1[切换原语]
a2[...]
end
a1--->CPU
subgraph B[内存]
PCB2
b1[指令1]
b2[...]
end
CPU--->b1在完成切换后,原进程所使用的系统资源会被新进程继续使用,这时就会存在一个问题:
原进程使用系统资源时,产生的相关信息会继续存放在系统资源内,当新进行继续使用时,产生的新的相关信息则会覆盖掉原信息如果此不做任何处理,那么当我们重新运行原进程时,就会因为丢失相关的信息而导致运行出错。
运行环境是指进程运行时所依赖和所处的全部条件、资源和状态的集合。我们将正在运行的进程所产生的相关信息称为该进程的上下文;
当我们在通过切换原语切换进程时,可以通过将该进程的运行环境以及上下文信息存储到该进程对应的 PCB 中。(为了方便理解,这里我们将该进程的 PCB 称为 PCB1)
完成切换后,系统会先通过读取新进程的 PCB 来恢复该进程的运行环境以及上下文(这里我们将新进程的PCB 称为 PCB2);
代码语言:javascript复制graph LR
subgraph A[内存]
subgraph PCB1
a[通用寄存器信息]
b[地址寄存器信息]
c[控制寄存器信息]
d[标志寄存器信息]
e[状态字]
f[...]
end
a1[指令1]
a2[指令2]
a3[切换原语]
end
a3--->CPU
subgraph B[内存]
subgraph PCB2
ba[通用寄存器信息]
bb[地址寄存器信息]
bc[控制寄存器信息]
bd[标志寄存器信息]
be[状态字]
bf[...]
end
b1[指令1]
b2[指令2]
b3[切换原语]
end
CPU--->b1
b3--->cpu[CPU]
subgraph C[内存]
subgraph PCB[PCB1]
aa[通用寄存器信息]
ab[地址寄存器信息]
ac[控制寄存器信息]
ad[标志寄存器信息]
ae[状态字]
af[...]
end
a4[指令3]
a5[指令4]
a6[切换原语]
end
cpu--->a4因此,切换原语的执行过程可以总结为2点:
记录旧进程的相关信息并改变旧进程的运行状态读取新进程的相关信息并改变新进程的运行状态其中进程的相关信息指的是进程当前的运行环境以及上下文。
结语今天的内容到这里就全部结束了。通过今天的学习,我们深入探讨了操作系统进程控制的核心机制。让我们回顾一下本文的重要知识点:
核心原语机制回顾
进程创建
进程创建原语完成了新进程的"诞生"过程,包括:
分配PID申请PCB分配资源初始化PCB将进程插入就绪队列我们了解了进程创建的四种典型场景:
用户登录作业调度系统服务用户程序请求 进程终止
进程终止原语负责进程的"善后工作",通过以下操作来实现进程的优雅退出:
检索PCB终止执行回收资源删除PCB导致进程终止总共有三种终止情况:
正常结束异常结束外界干预 阻塞与唤醒
阻塞与唤醒原语这对相辅相成的机制,实现了进程在运行态与阻塞态之间的智能转换。
特别需要注意的是,Block 和 Wakeup 必须成对使用,否则可能导致进程永久阻塞。
进程切换
进程切换原语作为多任务并发的关键技术,通过以下操作实现了进程间的平滑切换,确保了CPU资源的高效利用:
保存上下文更新PCB恢复运行环境,知识体系构建
这些原语共同构成了操作系统进程管理的基石,它们通过原子操作特性保证了进程状态转换的一致性和可靠性。
理解这四种原语的工作机制,不仅帮助我们掌握了进程生命周期管理的核心技术,更为后续学习进程同步、通信等高级主题奠定了坚实基础。
进程控制机制体现了操作系统设计的精妙之处——通过简单而可靠的原语操作,构建出复杂而强大的多任务环境。这种"简单构建复杂"的设计思想,值得我们深入体会和学习。
互动与分享
点赞👍 - 您的认可是我持续创作的最大动力
收藏⭐ - 方便随时回顾这些重要的基础概念
转发↗️ - 分享给更多可能需要的朋友
评论💬 - 欢迎留下您的宝贵意见或想讨论的话题
感谢您的耐心阅读! 关注博主,不错过更多技术干货。我们下一篇再见!