清华大学操作系统OS学习(十三)——死锁、进程通信、信号、管道、消息队列和共享内存

一、死锁概念

①死锁:一组阻塞的进程(两个或多个),持有一种资源,等待获取另一个进程所占有的资源,而导致谁都无法执行。 

②可重复使用的资源:

在一个时间只能一个进程使用,且不能被删除。OS避免杀死拥有资源的进程;进程使用资源后要释放,让其他进程重用;有物理资源(cpu, I/O通道,主和副存储器),也有抽象的资源(设备和数据结构,如文件,数据库和信号量);如果每个进程拥有一个资源并请求其他资源,可能导致死锁

③资源分配图

④死锁的必要条件

  • 互斥
  • 持有并等待
  • 无抢占,一个资源只能被进程自愿释放
  • 循环等待,形成闭环

二、死锁处理方法

1、死锁预防(dead-lock prevention )

①打破死锁出现的条件 ,确保系统永远不会进入死锁状态

②互斥—占用非共享资源 会增加不确定性 不推荐

③占用并等待—保证当一个进程请求资源时,不持有任何其他的资源

④all or nothing 需要进程请求并分配其所有资源,资源利用率低,可能饥饿

⑤无抢占—允许抢占占有某些资源的进程

⑥循环等待—对所有资源类型进行排序,并要求每个进程按照资源的顺序进行申请,会出现资源利用不够

2、死锁避免( deadlock avoidance )

①当进程运行过程中,根据申请资源的情况判断会不会死锁,如果会就不给资源。

②最简单有效就是要求每个进程声明它需要的每个类型资源的最大数目,资源在分配中根据最大数目限定提供与分配的资源数目,死锁避免算法要动态检查资源的分配状态来避免环形等待。

③环形等待不一定会死锁。分为安全状态,不安全状态,死锁状态,不安全状态包括死锁。

3、死锁检测和恢复(Deadlock Detection & Recovery)

在检测到运行系统进入死锁状态后,进行恢复

4、由应用程序处理死锁

通常操作系统忽略死锁,大多数操作系统(包括UNIX)的做法

5、安全状态、不安全状态和死锁

当一个进程请求可用资源,系统必须判断分配资源是否能让系统处于安全状态。

①、安全状态:针对所有进程,存在安全的时间序列。第一个P1结束,第二个P2结束。。。都能得到满足,正常结束。则称序列< P1, P2…Pn >是安全的:针对每一个进程Pi,它要求的资源能够由当前可用的资源+所有i之前的进程所持有的资源来满足。

进程会相继结束,Pi只能用它之前的进程的资源。

如果Pi资源的需求不是立即可用,那么Pi可以等到所有Pj完成。

当Pi完成后Pi+1得到所需要的资源,执行,释放资源,并终止。

②避免死锁: 确保系统永远不会进入不安全状态

如果系统处于安全状态 => 没有死锁

如果处于不安全状态 => 可能死锁

关系:安全与不安全互斥;不安全包含死锁。

三、银行家算法

1、有多个资源实例 ;每个进程必须能最大限度地利用资源 ;一个进程请求一个资源时,不得不等待 ;所有资源都必须在一段有效时间释放 ;找到理想执行时序,找到就认为是安全的

类比:银行家——操作系统;资金——资源;客户——申请资源的线程

2、银行家算法:数据结构

n=线程数量 m=资源类型数量(一个线程可能需要多种资源)

Max 总需求量:n*m矩阵 max[i, j]=k 进程Pi最多需要资源类型Rj的k个实例

Available 剩余空闲量:长度为m的向量,如果available[j]=k 则有k个类型Rj的资源实例可用

Allocation 已分配量:n*m矩阵 allocation[I, j]=k 进程Pi已经分配了资源类型Rj的k个实例

Need 未来需要量: n*m矩阵 need[i, j]=k 进程Pi可能需要资源类型Rj的k个实例

Max[i, j]=need[I,j]+allocation[i,j]

3、安全状态判断

四、死锁检测

也是银行家算法,由于开销大,且需要一开始就知道max[i,j],不一定能得到,所以主要用于开发阶段的调试,不会用于检测,特别是单一OS时

先回收T0和T2,再T1-T3-T4

五、进程通信概念

1、进程通信( IPC: inter process communication)

①、进程通信:是进程进行通信和同步的机制

②、IPC facility 提供2个操作: send(message)、receive (message)

③、进程P和Q想通信,需要: 在它们之间建立通信链路 ,通过send/receive交换消息

④、通信链路的实现: 物理(例如,共享内存,硬件总线)、 逻辑(如逻辑属性)

⑤、通信方式:间接通信、直接通信

2、直接通信

①、为了实现直接通信,要有发送和接收的ID ;进程必须正确地命名对方 ;

send( P, message) - 发送信息到进程P ;receive( P, message) - 接收进程P的信息

②、通信链路的属性 :自动建立链路 ;一条链路对应一对通信进程 ;每对进程之间只有一个链接存在 ;链接可以是单向的,但通常为双向的

2、间接通信

①、为了实现间接通信,要发送到共享区,发送方和接收方都不关注具体的另一方是谁

定向从消息队列接收消息: 每个消息队列都有一个唯一的ID;只有共享了相同消息队列的进程,进程才能通信

②、通信链路的属性:只有共享了相同消息队列的进程,才建立链路;链接可以与许多进程相关联;链接可以是单向或双向

③、通信流程: Ⅰ、建立一个新的消息队列 ;Ⅱ、通过消息队列发送和接收消息 ;Ⅲ、销毁消息队列 

④、基本通信操作: 

send(A, message) – 发送消息到队列A 

receive(A, message) - 从队列A接受消息

3、阻塞与非阻塞通信

①、进程通信可划分为阻塞(同步)和非阻塞(异步)

②、阻塞通信:阻塞发送、阻塞接收

③、非阻塞通信:非阻塞发送、非阻塞接收

4、通信链路缓冲

队列的消息被附加到链路的3种方式 

①、0容量—0 messages 发送方必须等待接收方 

②、有限容量—n messages 的有限长度,发送方在队列满的时候要等待 

③、无限容量—理想状况,不用等

六、信号和管道

1、信号(Signal)

①、信号是进程间的软件中断通知和处理机制,如:SIGKILL,SIGSTOP等

②、信号的接收处理

Ⅰ、捕获 catch : 指定信号处理函数被调用

Ⅱ、忽略 ignore: 依靠操作系统的默认操作 , 如进程终止、进程挂起

Ⅲ、屏蔽 mask:禁止进程接收和处理信号(可能是暂时的,当处理同样类型的信号)

不足:不能传输要交换的任何数据

优点:效率很高,异步。一般处理完后会回到被打断的进程。

③、信号的实现

2、管道

①、管道是进程间基于内存文件的通信机制。子进程从父进程继承包括文件描述符等的资源。进程不知道另一端:可能从键盘、文件、程序读取;可能写入终端、文件、程序。

②、与管道相关的系统调用

Ⅰ、读管道:read(fd,buffer,nbytes) 如scanf()是基于它实现的

Ⅱ、写管道:write(fd,buffer,nbytes) 如printf()是基于它实现的

Ⅲ、创建管道:pipe(rgfd) rgfd是2个文件描述符组成的数组

rgfd[0]是读文件描述符;rgfd[1]是写文件描述符

③管道示例

UNIX想灵活组合小程序,一个的输出是另一个的输入,用竖线|来表示把ls的输出stdout重定向,通过一个类似buffer的管道作为stdin传输给more。More以为是从i/o给它的,实际是ls给它的。进程不关心。 

七、消息队列和共享内存

1、消息队列

管道必须有父进程,数据是字节流,没有数据结构。消息队列可以多个不相干的进程来传递数据,而且message作为一个字节序列存储,message quenues是消息数组。是一个有意义的结构化。 按FIFO/FILO管理 

①消息队列是由操作系统维护的以字节序列为基本单位的间接通信机制。每个消息是一个字节序列;相同标识的消息组成按先进先出顺序组成一个消息队列。

②消息队列的系统调用

msgget(key,flags)获取消息队列标识

msgsnd(QID,buf,size,flags)发送消息

msgrcv(QID,buf,size,type,flags)接收消息

msgctl(...)消息队列控制

2、共享内存

①共享内存是把同一个物理内存区域同时映射到多个进程的内存地址空间的通信机制。

②每个进程都有私有内存地址空间;每个进程的内存地址空间需明确设置共享内存段;

同一进程中的线程总是共享相同的内存地址空间

③优点:快速、方便地共享数据;

缺点:必须用额外的同步机制来协调数据访问

④共享内存是最快的方法,一个进程写另一个进程立即可见,没有系统调用干预,没有数据复制。

⑤共享内存系统调用

shmget(key,size,flags)创建共享段

shmat(shmid,*shmaddr,flags)把共享段映射到进程地址空间

shmdt(*shmaddr)取消共享段到进程地址空间的映射

shmctl(...)共享段控制

需要信号量等机制协调共享内存的访问冲突。

猜你喜欢

转载自blog.csdn.net/qq_36552489/article/details/92837963