正在学习操作系统,记录笔记。
参考资料: 《操作系统(精髓与设计原理 第6版) 》
在给进程下定义之前,我们先回顾总结一下第一章和第二章的概念。
操作系统需要以一个有序的方式管理应用程序的执行,以达到以下目的:
下面给出进程(process)的4个定义:
进程的两个基本元素是程序代码(可能被执行相同程序的其他进程共享)和代码相关联的数据集。
进程控制块(Process Control Block)
进程控制块是一种数据结构,该控制块由操作系统创建和管理。其中包含了以下信息:
关于进程控制块的几点说明:
进程控制块包含了充分的信息,这样就可以中断一个进程的执行,并且在后来恢复执行进程时就好像进程未被中断过。进程控制块是操作系统能够支持多进程和提供多处理的关键工具。当进程被中断时,操作系统会把程序计数器和处理器寄存器(上下文数据)保存到进程控制块中的相应位置,进程状态也被改变为其他的值(例如阻塞状态或就绪状态)。
关于进程和程序的差异:
关于并行和并发:
进程轨迹(Trace of Process)
进程轨迹就是:进程执行的指令序列。
调度器(Dispatcher)/分派器可以使处理器从一个进程切换到另一个进程。
对一个被执行的程序,操作系统会为该程序创建一个进程或任务。从处理器的角度看,它在指令序列中按某种顺序执行指令,这个顺序根据程序计数器寄存器中不断变化的值来指示,程序计数器可能指向不同进程中不同部分的程序代码;从程序自身的角度看,它的执行涉及程序中的一系列指令。
上图给出了三个进程在内存中的布局,其中进程A和C执行12条指令,进程B执行4条指令(如下图)
现在假设编号为8003的指令执行 后进程必须等待I/O操作,且操作系统仅允许一个进程最多连续执行6个指令周期。下图给出了最初的52个指令周期中交替的轨迹。
(阴影部分表示调度器程序的执行)
指令执行图并不实用,看起来过于繁杂,于是引入了进程模型。下面将会分别介绍两状态进程模型、五状态进程模型以及七状态进程模型。
该模型下的进程有两种状态:运行态(Running)以及非运行态(Not-running)
四种状态:
从上面这个简单的模型中进而可以分析道,必须通过某种方式来表示进程,从而使操作系统可以跟踪它们。未运行的进程必须保持在某种类型的队列中,并等待它们的执行时机。下图给出了一个队列结构,队列中的每一项都指向某个特定进程的指针。(队列也可以由数据块构成的链表组成,每个数据块表示一个进程)。
可以用该排队图描述分派器的行为。被中断的进程转移到等待进程队列中,或者,如果进程已经结束或取消,则被销毁(离开系统)。在任何一种情况下,分派器均从队列中选择一个进程来执行。
导致进程创建的原因(4类):
事件 | 说明 |
---|---|
新的批处理作业 | 通常位于磁带或磁盘中的批处理作业控制流被提供给操作系统。当操作系统准备接纳新工作时,它将读取下一个作业控制命令 |
交互登录 | 终端用户登录到系统 |
操作系统因为提供一项服务而创建 | 操作系统可以创建一个进程,代表用户程序执行一个功能,使用户无需等待(如控制打印的进程) |
由现有的进程派生 | 基于模块化的考虑,或者为了开发并行性,用户程序可以指示创建多个进程 |
当操作系统位另一个进程的显示请求创建一个进程时,这个动作被称为进程派生。当一个进程派生另一个进程时,前一个称作父进程,被派生的叫做子进程。
导致进程终止的事件(我们大致可以分为三类):
还有一些具体导致进程终止的原因可见下表:
事件 | 说明 |
---|---|
正常完成 | 进程自行执行一个操作系统服务调用,表示它已经结束运行 |
超过时限 | 进程运行时间超过规定的时限。可以测量很多种类型的时间,包括总的运行时间(“挂钟时间”)、花费在执行上的时间以及对于交互进程从上一次用户输入到当前时刻的时间总量 |
无可用内存 | 系统无法满足进程需要的内存空间 |
越界 | 进程试图访问不允许访问的内存单元 |
保护错误 | 进程试图使用不允许使用的资源或文件,或者试图以一种不正确的方式使用,如往只读文件中写 |
算数错误 | 进程试图进行被禁止的计算,如除以零或者存储大于硬件可以接纳的数字 |
时间超出 | 进程等待某一事件发生的时间超过了规定的最大值 |
I/O失败 | 在输入或输出期间发生错误,如找不到文件、在超过规定的最多努力次数后仍然读/写失败(例如当遇到了磁带上的一个坏区时)或者无效操作(如从行式打印机中读) |
无效指令 | 进程试图执行一个不存在的指令(通常是由于转移到了数据区并企图执行数据) |
特权指令 | 进程试图使用为操作系统保留的指令 |
数据误用 | 错误类型或未初始化的一块数据 |
操作员或操作系统干涉 | 由于某些原因,操作员或操作系统终止进程(例如,如果存在死锁) |
父进程终止 | 当一个父进程终止时,操作系统可能会自动终止该进程的所有后代进程 |
父进程请求 | 父进程通常具有终止其任何后代进程的权力 |
引入五状态模型的原因:
对于之前介绍的两状态模型,处理器会对可运行的进程以一种轮转(round-robin)的方式操作(依次给队列中的每一个进程一定的执行时间,然后进程返回队列,阻塞情况除外)。但是这种方式存在两类问题:
解决上述问题的方法就是将非运行状态再细分为两种状态:就绪态(Ready)和阻塞态(Blocked)。因此就出现了如下图所示的五状态模型。
它分别有:
五状态模型中的9种事件类型:
下图给出了进程在不同状态间转换时可能实现的排队规则:
有两个队列:就绪队列和阻塞队列。进入系统的每个进程被放置在就绪队列中,当操作系统选择另一个进程运行时,将从就绪队列中选择。当一个正在运行的进程被移出处理器时,它根据情况或者被终止,或者被放置在就绪或阻塞队列中。最后,当一个事件发生时,所有位于阻塞队列中等待这个事件的进程都被转换到就绪队列中。
上述方案意味着当一个事件发生时,操作系统必须扫描整个阻塞队列,搜所那些等待该事件的进程。但是在大型操作系统中,队列中可能存在几百甚至上千个进程,所以拥有多个队列将会更有效,一个事件可以对应一个队列,这样在某事件发生时,相应队列中的所有进程都将转换到就绪态。
最后还有一种改进:按照优先级方案分配进程,维护多个就绪队列(每个优先级一个队列)将会带来更多便利。操作系统就可以很容易地确定哪个就绪进程具有最高地优先级且等待事件最长。
实际上,由于I/O活动比计算机速度慢得多,内存中可以保有多个进程,当一个进程在等待时(比如I/O),处理器可以转移到另一个进程。即便如此,上述方案可能导致的一种常见的情况是:内存中有很多进程都在等待I/O。多道程序设计并不能从根本解决问题,大多数时候处理器仍可能处于空闲状态。
一种解决办法就是扩大内存,使其能够载入更多的进程。但是这种办法有两个严重的问题:一是内存价格的问题,从第一章的内容可以看出,扩大内存需要付出很大经济代价。第二个问题是,内存的扩大更可能导致带来更大的进程,而非更多的进程。
所以就出现了第二种解决办法:交换(swapping)
交换:把内存中某个进程的一部分或者全部转移到外存(磁盘)中。
交换概念就带来了**挂起(suspend)**状态:当内存中没有处于就绪状态的进程时,操作系统就把被阻塞的进程换出到磁盘的“挂起队列”(suspend queue)中。此后,操作系统可以从挂起队列中取出另一个进程,或者接受一个新进程的请求,将其纳入内存运行。
交换是一个I/O操作,但是由于磁盘I/O一般是系统中最快的I/O(相对于磁带或打印机),所以交换通常会提高性能。
由于交换的出现,又引入了七状态模型。
在原有五状态模型的基础上又新增了两个状态:
同样的,在五状态模型的9种事件类型的基础上又新增了7种事件类型:
挂起的特点(重新理解并定义):
下表展示了导致进程挂起的原因:
事件 | 说明 |
---|---|
交换 | 操作系统需要释放足够的内存空间,以调入并执行处于就绪状态的进程 |
其他OS原因 | 操作系统可能挂起后台进程或工具程序进程,或者被怀疑导致问题的进程 |
交互式用户请求 | 用户可能希望挂起一个程序的执行,目的是为了调试或者与一个资源的使用进行连接 |
定时 | 一个进程可能会周期性地执行(例如记账或系统监视进程),而且可能在等待下一个时间间隔时被挂起 |
父进程请求 | 父进程可能会希望挂起后代进程的执行,以检查或修改挂起的进程,或者协调不同后代进程之间的行为 |
进程和资源(Processes and Resources)
在多道程序设计环境中,在虚拟内存中有许多已经创建了的进程(P1,…,Pn),每个进程在执行期间,需要访问某些系统资源,包括处理器、I/O设备和内存。在图中,进程P1正在运行,该进程至少有一部分在内存中,并且还控制着两个I/O设备;进程P2也在内存中,但由于正在等待分配给P1的I/O设备而被阻塞;进程Pn已经被换出,因此是挂起的。
操作系统的控制结构(Operating System Control Structures)
操作系统为了管理进程和资源,必须掌握关于每个进程和资源当前状态的信息。普遍使用的方法是:操作系统构造并维护它所管理的每个实体的信息表。在一般情况下,操作系统维护着4种不同类型的表:内存表(Memory Tables)、I/O表(I/O Tables)、文件表(File Tables)、进程表(Process Table)。
进程最少必须包括一个或一组被执行的程序,与这些程序相关联的是局部变量、全局变量和任何已定义常量的数据单元。程序的执行通常涉及用于跟踪过程调用和过程间参数传递的栈。与每个进程相关联的还有操作系统用于控制进程的许多属性,通常,属性的集合称为进程控制块(PCB)。
进程控制块信息可以分为以下三类:
进程控制块中的典型元素见下表: 进程标识信息 元素 说明 标识符 存储在进程控制块中的数字标识符,包括 · 此进程的标识符(Process ID,简称进程ID) · 创建这个进程的进程(父进程)标识符 · 用户标识符(UserID,简称用户ID) 处理器状态信息 元素 说明 用户可见寄存器 用户可见寄存器是处于用户态的处理器执行的机器语言可以访问的寄存器。通常有8到32个此类寄存器,而在一些RISC实现中有超过100个此类寄存器 控制和状态寄存器 用于控制处理器操作的各种处理器寄存器,包括: · 程序计数器:包含将要取的下一条指令的地址 · 条件码:最近的算术或逻辑运算的结果(例如符号、零、进位、等于、溢出) · 状态信息:包括中断允许/禁用标志、异常模式 栈指针 每个进程有一个或多个与之相关联的后进先出(LIFO)系统栈。栈用于保存参数和过程调用或系统调用的地址,栈指针指向栈顶 进程控制信息 元素 说明 调度和状态信息 这是操作系统执行其调度功能所需要的信息,典型的信息项包括: · 进程状态:定义将被调度执行的进程的准备情况(例如运行态、就绪态、等待态、停止态) · 优先级:用于描述进程调度优先级的一个或多个域。在某些系统中,需要多个值(例如默认、当前、最高许可) · 调度相关信息:这取决于所使用的调度算法。例如进程等待的时间总量和进程在上一次运行时执行时间总量 · 事件:进程在继续执行前等待的事件标识 数据结构 进程可以以队列、环或者别的结构形式与其他进程进行链接。例如,所有具有某一特定优先级且处于等待状态的进程可链接在一个队列中;进程还可以表示出与另一个进程的父子(创建者-被创建者)关系。进程控制块为支持这些结构需要包含指向其他进程的指针 进程间通信 与两个独立进程间的通信相关联的各种标记、信号和信息。进程控制块中维护着某些或全部此类信息 进程特权 进程根据其可以访问的内存空间以及可以执行的指令类型被赋予各种特权。此外,特权还用于系统实用程序和服务的使用 存储管理 这一部分包括指向描述分配给该进程的虚拟内存空间的段表和页表的指针 资源的所有权和使用情况 进程控制的资源可以表示成诸如一个打开的文件,还可能包括处理器或其他资源的使用历史;调度器会需要这些信息
实际上在所有的操作系统中,对于进程标识符,每个进程都分配了一个唯一的数字标识符。进程标识符可以简单地表示为主进程表中的一个索引;否则,必须有一个映射,使得操作系统可以根据进程标识符定位相应的表。 除了进程标识符,还给进程分配了一个用户标识符,用于标明拥有该进程的用户。
执行模式(Modes of Execution)
大多数处理器至少支持两种执行模式:用户模式(User mode)以及内核模式(kernel mode)
用户模式:
内核模式:
使用两种模式的原因是很显然的,它可以保护操作系统和重要的操作系统表(如进程控制块)不受用户程序的干涉。在内核态下,软件具有对处理器以及所有指令、寄存器和内存的控制能力,这一级的控制对用户程序不是必需的,并且为了安全起见也不是用户程序可访问的。
两种模式的切换
程序状态字中有一位表示执行模式,这一位应某些事件的要求而改变。在典型情况下,当用户调用一个操作系统服务或中断触发系统例程的执行时,执行模式被设置成内核态,当从系统服务返回到用户进程时,执行模式被设置为用户态。处理器状态寄存器(Processor status register ,PSR)中包含当前特权级别(Current privileged level,CPL)。当执行不同的进程时,操作系统会根据需要对CPL进行置位或清零的操作去改变其模式(通常数字越小,级别越大)。
进程创建(Process Creation)
进程创建的步骤按如下5步进行:
进程切换(Process Switching)
引发进程切换的原因:
模式切换VS进程切换
模式切换:
(当中断发生时)
进程切换:
模式切换较进程切换的代价要小。 进程切换一定包含模式切换;但是模式切换不一定包含进程切换。
操作系统的执行(Execution of the Operating System)
操作系统与普通计算机软件一样由处理器执行,同样的,操作系统也是一个进程。下面介绍关于如何控制这种进程。
无进程的内核(Non-process Kernel)
在用户进程中执行(Execution Within User Processes)
基于进程的操作系统(Process-Based Operating System)
本篇已完结
(如有修改或补充欢迎评论)