进程管理 进程# 进程是程序的一次执行 是一个程序及其数据在处理机上顺序执行时所发生的活动 是具有独立功能的程序在一个数据集合上的一次运行过程 是系统进行资源分配和调度的一个基本单位PCB结构、程序和数据的集合 设备分配只针对现有进程,不会创建进程 进程的特征:

进程与程序的区别:

进程状态及其演变# 进程执行的间断性,决定了进程可能具有多种状态 基本状态# 运行的进程可能具有就绪、执行、阻塞三种基本状态

操作系统中进程的五种状态(深度解析操作系统原理之进程管理)(1)

当进程已分配到除CPU以外的所有必要资源时,它便处于就绪状态,一旦获得CPU,便立即执行,进入执行状态 正在执行的进程,由于发生某个事件而暂时无法执行时,便放弃处理机而进入阻塞状态 由于执行的进程变为阻塞状态后,调度程序立即把处理机分配给另一个就绪进程(因此,阻塞进程的事件消失后,进程不会立即恢复到执行状态,而转变为就绪状态,重新等待处理机) 创建和终止# 为了管理的需要,还存在着两种比较常见的进程状态,即创建状态和终止状态

操作系统中进程的五种状态(深度解析操作系统原理之进程管理)(2)

创建状态: 引起创建的事件:

  1. 用户登录
  2. 作业调度:为被调度的作业创建进程
  3. 提供服务:要求打印
  4. 应用请求

创建一个进程一般要通过两个步骤:

当一个新进程被创建时,系统已为其分配了PCB,填写了进程标识等信息,但由于该进程所必需的资源或其它信息,如主存资源尚未分配等,一般而言,此时的进程已拥有了自己的PCB,但进程自身还未进入主存,即创建工作尚未完成,进程还不能被调度运行,其所处的状态就是创建状态。 引入创建状态,是为了保证进程的调度必须在创建工作完成后进行,以确保对进程控制块操作的完整性。同时,创建状态的引入,也增加了管理的灵活性,操作系统可以根据系统性能或主存容量的限制,推迟创建状态进程的提交。对于处于创建状态的进程,获得了其所必需的资源,以及对其PCB初始化工作完成后,进程状态便可由创建状态转入就绪状态。 终止状态: 引起终止的事件:

  1. 正常结束
  2. 异常结束
  3. 外界干预
  4. 系统管理员kill
  5. 父进程终止
  6. 父进程请求

进程的终止也要通过两个步骤:

一个进程到达了自然结束点,或是出现了无法克服的错误,或是被操作系统所终结,或是被其他有终止权的进程所终结,它将进入终止状态 进入终止态的进程以后不能再执行,但在操作系统中依然保留一个记录,其中保存状态码和一些计时统计数据,供其它进程收集。一旦其它进程完成了对终止状态进程的信息提取之后,操作系统将删除该进程。 阻塞和唤醒# 阻塞是进程自身的一种主动行为 a. 调用block原语 b. 停止执行,修改PCB进入阻塞队列(一个或多个 唤醒由其他相关进程完成 a. wakeup原语 b. 修改PCB进入就绪队列 挂起# 为了系统和用户观察分析的需要,还引入了挂起操作,与挂起对应的是激活操作 当进程被挂起,便会进入静止状态:正在执行,便会暂停执行,处于就绪状态则不接受调度 引入挂起状态的原因有:

在引入挂起状态后:

操作系统中进程的五种状态(深度解析操作系统原理之进程管理)(3)

相关视频推荐

进程与CPU的故事

初识Linux内核,进程通信能这么玩

linux内核,进程调度器的实现,完全公平调度器 CFS

C/C Linux服务器开发/后台架构师【零声教育】-学习视频教程-腾讯课堂

【文章福利】:小编整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!~点击加入(832218493需要自取)

操作系统中进程的五种状态(深度解析操作系统原理之进程管理)(4)

五个进程状态的转换#

操作系统中进程的五种状态(深度解析操作系统原理之进程管理)(5)

PCB# 为了描述和控制进程的运行,系统为每个进程定义了一个数据结构——进程控制块PCB(Process Control Block),它是进程实体的一部分,是操作系统中最重要的记录型数据结构 PCB 的作用是使一个在多道程序环境下不能独立运行的程序(含数据),成为一个能独立运行的基本单位,一个能与其它进程并发执行的进程

  1. 作为独立运行基本单位的标志
  2. 能实现间断性的运行方式
  3. 提供进程管理所需要的信息
  4. 提供进程调度所需要的信息
  5. 实现与其他进程的同步与通信

PCB中的信息:#

  1. 进程标识符:用于惟一地标识一个进程,一个进程通常有两种标识符:
  2. 内部标识符,在所有的操作系统中,都为每一个进程赋予了一个惟一的数字标识符, 它通常是一个进程的序号。设置内部标识符主要是为了方便系统使用。
  3. 外部标识符,它由创建者提供,通常是由字母、数字组成,往往是由用户(进程)在访问该进程时使用。为了描述进程的家族关系,还应设置父进程标识及子进程标识。此外,还可设置用户标识,以指示拥有该进程的用户。
  1. 处理机状态:主要是由处理机的各种寄存器中的内容组成的。处理机在运行时,许多信息都放在寄存器中。当处理机被中断时,所有这些信息都必须保存在PCB 中,以便在该进程重新执行时,能从断点继续执行。这些寄存器包括
  2. 通用寄存器,又称为用户可视寄存器,它们是用户程序可以访问的,用于暂存信息,在大多数处理机中,有 8~32 个通用寄存器,在RISC 结构的计算机中可超过100 个
  3. 指令计数器,其中存放了要访问的下一条指令的地址
  4. 程序状态字PSW,其中含有状态信息,如条件码、执行方式、中断屏蔽标志等
  5. 用户栈指针,指每个用户进程都有一个或若干个与之相关的系统栈,用于存放过程和系统调用参数及调用地址,栈指针指向该栈的栈顶。
  1. 进程调度信息:在 PCB中还存放一些与进程调度和进程对换有关的信息,包括
  2. 进程状态,指明进程的当前状态,作为进程调度和对换时的依据
  3. 进程优先级,用于描述进程使用处理机的优先级别的一个整数,优先级高的进程应优先获得处理机
  4. 进程调度所需的其它信息,它们与所采用的进程调度算法有关,比如,进程已等待CPU的时间总和、进程已执行的时间总和等
  5. 事件,指进程由执行状态转变为阻塞状态所等待发生的事件,即阻塞原因。
  1. 进程控制信息
  2. 程序和数据的地址,指进程的程序和数据所在的内存或外存地(首)址,以便再调度到该进程执行时,能从PCB中找到其程序和数据
  3. 进程同步和通信机制,指实现进程同步和进程通信时必需的机制,如消息队列指针、信号量等,它们可能全部或部分地放在PCB 中
  4. 资源清单,即一张列出了除CPU 以外的、进程所需的全部资源及已经分配到该进程的资源的清单
  5. 链接指针,它给出了本进程(PCB)所在队列中的下一个进程的PCB的首地址。

PCB的组织方式# 在一个系统中,通常可拥有数十个、数百个乃至数千个PCB。为了能对它们加以有效的管理,应该用适当的方式将这些PCB组织起来。目前常用的组织方式有以下两种。

  1. 线性方式:将系统种所有PCB都组织在一张线性表中,将该表首地址存在内存的一个专用区域 实现简单,开销小,但是每次都需要扫描整张表,适合进程数目不多的系统
  2. 链接方式:把同一状态的PCB链接成一个队列,形成就绪队列、若干个阻塞队列和空白队列等 对其中的就绪队列常按进程优先级的高低排列,优先级高排在队前,此外,也可根据阻塞原因的不同而把处于阻塞状态的进程的PCB排成等待I/O 操作完成的队列和等待分配内存的队列等
  3. 索引方式:系统根据所有进程的状态建立几张索引表,例如就绪索引表、阻塞索引表等,并把各索引表在内存的首地址记录在内存的一些专用单元中,在每个索引表的表目中,记录具有相应状态的某个PCB在PCB址

操作系统中进程的五种状态(深度解析操作系统原理之进程管理)(6)

操作系统中进程的五种状态(深度解析操作系统原理之进程管理)(7)

进程的控制# 进程控制是进程管理最基本的功能,主要包括创建新进程,终止已完成的进程,将发生异常的进程置于阻塞状态,进程运行中的状态转换等 进程创建# 参数:进程标识、优先级、进程起始地址、CPU初始状态、资源需求等等 创建进程的过程

  1. 创建一个空白PCB
  2. 为新进程分配所需资源
  3. 初始化PCB
  4. 标识信息,将系统分配的标识符和父进程标识符填入新PCB
  5. 处理机状态信息,使程序计数器指向程序入口地址,使栈指针指向栈顶
  6. 处理机控制信息,将进程设为就绪/静止状态,通常设为最低优先级
  1. 如果就绪队列能接纳,则插入

进程终止# 进程终止的时机/时间:

  1. 正常结束
  2. 异常结束
  3. 越界错,访问的存储区越出该进程的区域
  4. 保护错,试图访问不允许访问的资源,或以不适当的方式访问(写只读)
  5. 非法指令,试图执行不存在的指令(可能是程序错误地转移到数据区,数据当成了指令)
  6. 特权指令出错,用户进程试图执行一条只允许OS执行的指令
  7. 运行超时,执行时间超过指定的最大值
  8. 等待超时,进程等待某件事超过指定的最大值
  9. 算数运算错,试图执行被禁止的运算(被0除)
  10. I/O故障
  1. 外界干预
  2. 操作员或OS干预(死锁)
  3. 父进程请求,子进程完成父进程指定的任务时
  4. 父进程终止,所有子进程都应该结束

终止过程

  1. 根据被终止进程的标识符,从PCB集合中检索出该PCB,读取进程状态
  2. 若处于执行状态:立即终止执行,置调度标志为true,指示该进程被终止后重新调度
  3. 若进程有子孙进程:将其所有子孙进程终止
  4. 全部资源还给父进程/OS
  5. PCB从所在队列/链表中移出

进程阻塞# 阻塞的时机/事件

  1. 请求共享资源失败,系统无足够资源分配
  2. 等待某种操作完成
  3. 新数据尚未到达(相互合作的进程)
  4. 等待新任务

阻塞过程:进程通过block 进程唤醒# 原语wakeup,和阻塞成对使用 唤醒过程:先把被阻塞的进程从该事件阻塞队列移出,将其PSB状态改为就绪,再插入就绪队列 进程同步# 制约关系#

临界资源:一次只允许一个进程访问的资源

临界区#

while(1){ entry; //进入区 critical; //临界区 exit; //退出区 }

同步机制应该遵循:

整形信号量# 信号量机制是一种进程间的低级通信方式 s是一个整形量,除了初始化外,仅通过两个原子操作wait(s)和signal(s)访问(也叫P,V操作)

wait(s){ while(s<=0); s--; } signal(s){ s ; }

互斥关系:A,B共享一个缓冲区,互斥

PA(){ while(1){ wait(s); // 临界区 signal(s); // 剩余区 } } PB(){ while(1){ wait(s); // 临界区 signal(s); // 剩余区 } } main(){ s=1; //init // begin PA(); PB(); // end }

前驱关系:P1,P2同步,P2→P1

PA(){ P(s); a1; } PB(){ a2; V(s); }

总结:

信号量表示的是临界资源数 初值为2,表示初始时有2个可用的资源,若现在为-1,说明这两个可用资源已经被占用了,而且有一个进程在等待资源 初值为3,表示初始时有3个可用的资源,若现在为1,表示有两个资源被进程访问了,可用资源变为1,没有进程会等待 为了使两个进程同步运行,至少2个信号量

例题#

1.桌上有一空盘,允许存放一只水果,爸爸可向盘内放苹果或桔子,儿子专等吃桔子,女儿专等吃苹果

semaphore s,so,sa=1,0,0; father(){ while(1) { wait(s); // 将水果放入盘中; if(放入的是桔子) then signal(so); else signal(sa); } } son(){ while(1){ wait(so); // 从盘中取出桔子 signal(s); // 吃桔子 } } daughter() { while(1){ wait(sa); // 从盘中取出苹果 signal(s); // 吃苹果 } } main() { // cobegin father(); son(); daughter(); // coend }

2.某寺庙,有小、老和尚若干,由小和尚提水入缸供老和尚饮用,水缸可容10桶水,水取自同一个井中,水井窄,每次只能容一个桶取水,水桶总数3个,每次入缸取水桶仅为1桶,且不可同时进行,试给出有关取水,入水的算法

mutexj = 1; mutexg = 1; empty = 10; full = 0; count = 3; old(){ while(1) { wait(full); //缸中有无水 wait(count); //有无桶 wait(mutexg); //取水前 Fetch from gang; signal(mutexg); signal(count); signal(empty); //通知小 } } little(){ while(1) { wait(empty); //缸中有无空 wait(count); //有无桶 wait(mutexj); //取水前 Fetch from well; signal(mutexj); wait(mutexg); //倒水前 pour; signal(mutexg); signal(count); signal(full); //通知老 } }

记录型信号量# 整形信号量中S<=0就会不断地测试,未遵循让权等待,而是处于忙等 解决方案:建立一个进程链表list,连结所有等待该类资源的进程

typedef struct{ int value; struct process_control_block *list }semaphore; wait(semaphore *S){ S->value--; if(S->value < 0) block(S->list); } signal(semaphore *S){ S->value--; if(S->value <= 0) wakeup(S->list); }

  1. S->value>0时,表示系统中可用资源的数目
  2. 当S->value<0时,S->value的绝对值表示阻塞进程的数目
  3. 如果S->value的初值为1,表示只允许一个进程访问临界资源,此时的信号量转化为互斥信号量

AND信号量# 要么全分配,要么一个也不分配 不用时有可能发生死锁

Swait(s1,s2,…,sn){ while(1){ if (s1>=1& …&sn >=1){ for(i=1;i<=n;i ) si--; break; } else{ //将进程放入与找到的第一个si<1的si相关的阻塞队列中 //并将该进程的程序计数设置为swait操作的开始 } } } Ssignal(s1,s2,…,sn){ while(1){ for (i=1;i<=n;i ){ si ; //将与si关联的队列中等待的所有进程都移动到就绪队列中 } } }

信号量集# 为提高效率而对AND信号量的扩充 允许一次申请多种资源多个 ti为分配下限值,Si>=ti则不分配,di为该进程需求值

Swait(S1, t1, d1, …, Sn, tn, dn){ while(1){ if(Si>=ti& … &Sn>=tn) for (i=1;i<=n;i ) Si=Si-di; else{ //将进程放在Si<ti的第一个Si的阻塞队列中 //并将该进程的程序计数设置为swait操作的开始 } } } Ssignal(S1, d1, …, Sn, dn){ while(1){ for (i=1;i<=n;i ) { Si =Si di; //将与si关联的队列中等待的所有进程都移动到就绪队列中 } } }

Swait(S,d,d):允许每次申请d个资源,少于d不分配 Swait(S,1,1):S>1记录型信号量,S=1互斥形信号量 Swait(S,1,0):可控开关,S>=1时允许同时进入,S<1时不允许 经典进程同步问题# 生产者-消费者*# 定义数据结构

int n; typedef item = xxx; //产品类型 item buffer [n]; //缓冲池 int in = 0,out = 0; int counter = 0; //产品数

缓冲池满时,生产者等待;为空时,消费者等待 记录型信号量

semaphore mutex=1,empty=n,full=0 item buffer[n]; //缓冲池 int in = 0,out = 0; int main() { cobegin: producer(); consumer(); coend } producer(){ while(1){ … produce an item in nextp; … wait(empty); wait(mutex); buffer[in]=nextp; in=(in 1)%n; signal(mutex); signal(full); } } consumer(){ while(1) { wait(full); wait(mutex); nextc=buffer[out]; out=(out 1)%n; signal(mutex); signal(empty); consumer the item in nextc; } }

P操作的顺序至关重要,顺序不当可能导致死锁(有缓冲池使用权,无缓冲) V操作的顺序无关紧要 当缓冲区只有一个时,mutex可省略 AND信号量

semaphore mutex=1,empty=n,full=0; item buffer[n]; int in=0,out=0; main(){ cobegin producer(); consumer(); coend } producer() { while(1) { ... produce......; ... Swait(empty,mutex); buffer[int]=nextp; in = (in 1)mod n; Ssignal(mutex,full); } } consumer(){ while(1){ Swait(full,mutex); nextc=buffer[out]; out=(out 1)%n; Ssignal(mutex,empty); consumer......; } }

哲学家进餐#

操作系统中进程的五种状态(深度解析操作系统原理之进程管理)(8)

5个哲学家围坐,用5只筷子吃面,筷子交替摆放 记录型信号量 设5个信号量表示5只筷子 AND信号量 同上 读-写*# 读进程可共享对象,写进程不可 设整形变量readcount读者数wmutex读写互斥,rmutex互斥访问 记录型信号量:

semaphore rmutex=1,wmutex=1; int readcount=0; int main(){ cobegin: reader(); writer(); coend; } reader(){ while(1){ wait(rmutex); if(readcount==0) wait(wmutex);//无人读才能写 readcount ; signal(rmutex); ... read...... ... wait(rmutex); readcount--; if(readcount==0) signal(wmutex); signal(rmutex); } } writer(){ while(1){ wait(wmutex); ... write...... ... signal(wmutex); } }

写优先

semaphore rmutex=1,wmutex=1,s=1; int readcount=0; int main(){ cobegin: reader(); writer(); coend; } reader(){ while(1){ wait(s);//! wait(rmutex); if(readcount==0) wait(wmutex);//无人读 readcount ; signal(rmutex); signal(s);//! ... read...... ... wait(rmutex); readcount--; if(readcount==0) signal(wmutex); signal(rmutex); } } writer(){ while(1){ wait(s);//! wait(wmutex); ... write...... ... signal(wmutex); signal(s);//! } }

信号量集

#define RN 20//最大读者数 semaphore L=RN,mx=1; int main(){ cobegin: reader(); writer(); coend; } reader(){ while(1){ swait(L,1,1); swait(mx,1,0); ... read...... ... wait(rmutex); ssignal(L,1); } } writer(){ while(1){ swait(mx,1,1); swait(L,RN,0); ... write...... ... ssignal(mx,1); } }

管程# 将同步操作的机制和临界资源结合到一起,避免了要使用临界资源的进程自备同步操作 管程:一个数据结构能为并发进程所执行的一组操作 包括:1. 局部对于管程的共享变量,2. 对该数据结构操作的一组过程,3. 对局部管程数据设初值

操作系统中进程的五种状态(深度解析操作系统原理之进程管理)(9)

Monitor m_name{ //管程名 variable declarations; //共享变量说明 cond declarations; //条件变量说明 public: //能被进程调用的过程 void P1(…); //对数据结构的操作过程 {} void P2(…); {} ... void Pn(…); {} ... { //管程主体 //初始化代码 } }

生产者-消费者# 建立管程PC,包括:

Monitor PC{ item buffer[N]; int in out; condition notfull,notempty; int count; public: void put(item x){ if(count>=N)cwait(notfull); buffer[in]=x; in=(in 1)%N; count ; csignal(notempty); } void get(item x){ if(count<=0)cwait(notempty); x=buffer[out]; out=(out 1)%N; count--; csignal(notfull); } } void producer(){ item x; while(1){ //produce PC.put(x); } } void consumer(){ item x; while(1){ PC.get(x); //consume } }

,