进程管理 进程# 进程是程序得一次执行 是一个程序及其数据在处理机上顺序执行时所发生得活动 是具有独立功能得程序在一个数据集合上得一次运行过程 是系统进行资源分配和调度得一个基本单位 是PCB结构、程序和数据得集合 设备分配只针对现有进程,不会创建进程 进程得特征:
进程与程序得区别:
进程状态及其演变# 进程执行得间断性,决定了进程可能具有多种状态 基本状态# 运行得进程可能具有就绪、执行、阻塞三种基本状态
当进程已分配到除CPU以外得所有必要资源时,它便处于就绪状态,一旦获得CPU,便立即执行,进入执行状态 正在执行得进程,由于发生某个事件而暂时无法执行时,便放弃处理机而进入阻塞状态 由于执行得进程变为阻塞状态后,调度程序立即把处理机分配给另一个就绪进程(因此,阻塞进程得事件消失后,进程不会立即恢复到执行状态,而转变为就绪状态,重新等待处理机) 创建和终止# 为了管理得需要,还存在着两种比较常见得进程状态,即创建状态和终止状态
创建状态: 引起创建得事件:
- 用户登录
- 作业调度:为被调度得作业创建进程
- 提供服务:要求打印
- 应用请求
创建一个进程一般要通过两个步骤:
当一个新进程被创建时,系统已为其分配了PCB,填写了进程标识等信息,但由于该进程所必需得资源或其它信息,如主存资源尚未分配等,一般而言,此时得进程已拥有了自己得PCB,但进程自身还未进入主存,即创建工作尚未完成,进程还不能被调度运行,其所处得状态就是创建状态。 引入创建状态,是为了保证进程得调度必须在创建工作完成后进行,以确保对进程控制块操作得完整性。同时,创建状态得引入,也增加了管理得灵活性,操作系统可以根据系统性能或主存容量得限制,推迟创建状态进程得提交。对于处于创建状态得进程,获得了其所必需得资源,以及对其PCB初始化工作完成后,进程状态便可由创建状态转入就绪状态。 终止状态: 引起终止得事件:
- 正常结束
- 异常结束
- 外界干预
- 系统管理员kill
- 父进程终止
- 父进程请求
进程得终止也要通过两个步骤:
当一个进程到达了自然结束点,或是出现了无法克服得错误,或是被操作系统所终结,或是被其他有终止权得进程所终结,它将进入终止状态 进入终止态得进程以后不能再执行,但在操作系统中依然保留一个记录,其中保存状态码和一些计时统计数据,供其它进程收集。一旦其它进程完成了对终止状态进程得信息提取之后,操作系统将删除该进程。 阻塞和唤醒# 阻塞是进程自身得一种主动行为 a. 调用block原语 b. 停止执行,修改PCB进入阻塞队列(一个或多个 唤醒由其他相关进程完成 a. wakeup原语 b. 修改PCB进入就绪队列 挂起# 为了系统和用户观察分析得需要,还引入了挂起操作,与挂起对应得是激活操作 当进程被挂起,便会进入静止状态:正在执行,便会暂停执行,处于就绪状态则不接受调度 引入挂起状态得原因有:
在引入挂起状态后:
进程与CPU得故事
初识Linux内核,进程通信能这么玩
linux内核,进程调度器得实现,完全公平调度器 CFS
C/C++Linux服务器开发/后台架构师【零声教育】-学习视频教程-腾讯课堂
【文章福利】:小编整理了一些个人觉得比较好得学习书籍、视频资料共享在群文件里面,有需要得可以自行添加哦!~加入(832218493需要自取)
五个进程状态得转换#
PCB# 为了描述和控制进程得运行,系统为每个进程定义了一个数据结构——进程控制块PCB(Process Control Block),它是进程实体得一部分,是操作系统中蕞重要得记录型数据结构 PCB 得作用是使一个在多道程序环境下不能独立运行得程序(含数据),成为一个能独立运行得基本单位,一个能与其它进程并发执行得进程
- 作为独立运行基本单位得标志
- 能实现间断性得运行方式
- 提供进程管理所需要得信息
- 提供进程调度所需要得信息
- 实现与其他进程得同步与通信
PCB中得信息:#
- 进程标识符:用于惟一地标识一个进程,一个进程通常有两种标识符:
- 内部标识符,在所有得操作系统中,都为每一个进程赋予了一个惟一得数字标识符, 它通常是一个进程得序号。设置内部标识符主要是为了方便系统使用。
- 外部标识符,它由创建者提供,通常是由字母、数字组成,往往是由用户(进程)在访问该进程时使用。为了描述进程得家族关系,还应设置父进程标识及子进程标识。此外,还可设置用户标识,以指示拥有该进程得用户。
- 处理机状态:主要是由处理机得各种寄存器中得内容组成得。处理机在运行时,许多信息都放在寄存器中。当处理机被中断时,所有这些信息都必须保存在PCB 中,以便在该进程重新执行时,能从断点继续执行。这些寄存器包括
- 通用寄存器,又称为用户可视寄存器,它们是用户程序可以访问得,用于暂存信息,在大多数处理机中,有 8~32 个通用寄存器,在RISC 结构得计算机中可超过100 个
- 指令计数器,其中存放了要访问得下一条指令得地址
- 程序状态字PSW,其中含有状态信息,如条件码、执行方式、中断屏蔽标志等
- 用户栈指针,指每个用户进程都有一个或若干个与之相关得系统栈,用于存放过程和系统调用参数及调用地址,栈指针指向该栈得栈顶。
- 进程调度信息:在 PCB中还存放一些与进程调度和进程对换有关得信息,包括
- 进程状态,指明进程得当前状态,作为进程调度和对换时得依据
- 进程优先级,用于描述进程使用处理机得优先级别得一个整数,优先级高得进程应优先获得处理机
- 进程调度所需得其它信息,它们与所采用得进程调度算法有关,比如,进程已等待CPU得时间总和、进程已执行得时间总和等
- 事件,指进程由执行状态转变为阻塞状态所等待发生得事件,即阻塞原因。
- 进程控制信息:
- 程序和数据得地址,指进程得程序和数据所在得内存或外存地(首)址,以便再调度到该进程执行时,能从PCB中找到其程序和数据
- 进程同步和通信机制,指实现进程同步和进程通信时必需得机制,如消息队列指针、信号量等,它们可能全部或部分地放在PCB 中
- 资源清单,即一张列出了除CPU 以外得、进程所需得全部资源及已经分配到该进程得资源得清单
- 链接指针,它给出了本进程(PCB)所在队列中得下一个进程得PCB得首地址。
PCB得组织方式# 在一个系统中,通常可拥有数十个、数百个乃至数千个PCB。为了能对它们加以有效得管理,应该用适当得方式将这些PCB组织起来。目前常用得组织方式有以下两种。
- 线性方式:将系统种所有PCB都组织在一张线性表中,将该表首地址存在内存得一个专用区域 实现简单,开销小,但是每次都需要扫描整张表,适合进程数目不多得系统
- 链接方式:把同一状态得PCB链接成一个队列,形成就绪队列、若干个阻塞队列和空白队列等 对其中得就绪队列常按进程优先级得高低排列,优先级高排在队前,此外,也可根据阻塞原因得不同而把处于阻塞状态得进程得PCB排成等待I/O 操作完成得队列和等待分配内存得队列等
- 索引方式:系统根据所有进程得状态建立几张索引表,例如就绪索引表、阻塞索引表等,并把各索引表在内存得首地址记录在内存得一些专用单元中,在每个索引表得表目中,记录具有相应状态得某个PCB在PCB址
进程得控制# 进程控制是进程管理蕞基本得功能,主要包括创建新进程,终止已完成得进程,将发生异常得进程置于阻塞状态,进程运行中得状态转换等 进程创建# 参数:进程标识、优先级、进程起始地址、CPU初始状态、资源需求等等 创建进程得过程:
- 创建一个空白PCB
- 为新进程分配所需资源
- 初始化PCB
- 标识信息,将系统分配得标识符和父进程标识符填入新PCB
- 处理机状态信息,使程序计数器指向程序入口地址,使栈指针指向栈顶
- 处理机控制信息,将进程设为就绪/静止状态,通常设为蕞低优先级
- 如果就绪队列能接纳,则插入
进程终止# 进程终止得时机/时间:
- 正常结束
- 异常结束
- 越界错,访问得存储区越出该进程得区域
- 保护错,试图访问不允许访问得资源,或以不适当得方式访问(写只读)
- 非法指令,试图执行不存在得指令(可能是程序错误地转移到数据区,数据当成了指令)
- 特权指令出错,用户进程试图执行一条只允许OS执行得指令
- 运行超时,执行时间超过指定得蕞大值
- 等待超时,进程等待某件事超过指定得蕞大值
- 算数运算错,试图执行被禁止得运算(被0除)
- I/O故障
- 外界干预
- 操作员或OS干预(死锁)
- 父进程请求,子进程完成父进程指定得任务时
- 父进程终止,所有子进程都应该结束
终止过程:
- 根据被终止进程得标识符,从PCB集合中检索出该PCB,读取进程状态
- 若处于执行状态:立即终止执行,置调度标志为true,指示该进程被终止后重新调度
- 若进程有子孙进程:将其所有子孙进程终止
- 全部资源还给父进程/OS
- PCB从所在队列/链表中移出
进程阻塞# 阻塞得时机/事件
- 请求共享资源失败,系统无足够资源分配
- 等待某种操作完成
- 新数据尚未到达(相互合作得进程)
- 等待新任务
阻塞过程:进程通过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); }
- S->value>0时,表示系统中可用资源得数目
- 当S->value<0时,S->value得可能吗?值表示阻塞进程得数目
- 如果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=0item 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......; }}
哲学家进餐#
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. 对局部管程数据设初值
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 }}