几种进程间的通信方式
管道( pipe ):
管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
有名管道 (named pipe) :
有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
信号量( semophore ) :
信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
消息队列( message queue ) :
消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
信号 ( signal ) :
信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
共享内存( shared memory ) :
共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
套接字( socket ) :
套接字也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同主机的进程通信。
死锁
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
产生条件
虽然进程在运行过程中,可能发生死锁,但死锁的发生也必须具备一定的条件,死锁的发生必须具备以下四个[必要条件]
1****)互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。
2****)请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。
3****)不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
4****)环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。
只要打破四个必要条件之一就能有效预防死锁的发生:
①打破互斥条件:改造独占性资源为虚拟资源,大部分资源已无法改造。
②打破不可抢占条件:当一进程占有一独占性资源后又申请一独占性资源而无法满足,则退出原占有的资源。
③打破占有且申请条件:采用资源预先分配策略,即进程运行前申请全部资源,满足则运行,不然就等待,这样就不会占有且申请。
④打破循环等待条件:实现资源有序分配策略,对所有设备实现分类编号,所有进程只能采用按序号递增的形式申请资源。即破坏了环路
银行家算法(适用于每种资源类型有多个实例)
为了实现银行家算法,必须要有几个数据结构:
注:设n为系统进程的个数,m为在资源类型的种类。
Available:长度为m的向量。表示每种资源的现有实例的数量。如果Available[j]=k,那么资源Rj有k个实例有效。
Max:n * m矩阵。定义每种进程的最大需求。如果Max[i][j]=k,那么进程Pi可以最多请求资源Rj的k个实例。
Allocation:n * m矩阵。定义每个进程现在所分配的各种资源类型的实例数量。如果Allocation[I,j]=k,那么进程Pj当前分配了k个资源Rj的实例。
Need:n * m矩阵。表示每个进程还需要的剩余的资源。如果Need[i][j]=k,那么进程Pj还需要资源Rj的k个实例。
注:Need[i][j] = Max[i][j] – Allocation [i][j]
为了描述方便,我们采用一些简化的表示方法:
设X和Y为长度为n的向量,则X <= Y当且仅当对所有i = 1,2,...,n,X[i] <= Y[i]。例如,如果X = (1,7,2,3)而Y = (0,3,2,1),那么Y <= X。如果Y <= X且Y != X,那么Y < X。
可以将Allocation和Need的每行作为向量,并分别用Allocation i和Need i来表示,向量Allocation i表示分配给进程Pi的资源;向量Need i表示进程为完成其任务可能仍然需要申请的额外资源。
银行家算法可整体分成两个部分:
1.安全性算法
确认计算机系统是否处于安全状态的算法分为如下几步:
(1)设Work和Finish分别为长度为m和n的向量。按如下方式进行初始化,Work = Avaliable且对于i = 0,1,...,n - 1,Finish[i] = false。
(2)查找这样的i使其满足
·Finish[i] = false
·Need i <= Work
如果没有这样的i,那么就转到第(4)步。
(3)Work = Work + Allocation i
Finish[i] = true
返回第(2)步
(4)如果对所有i,Finish[i] = true,那么系统则处于安全状态。
该算法可能需要m * n^2数量级的操作以确定系统是否处于安全状态。
2.资源请求算法
现在,描述如何判断是否可安全允许请求的算法。
设Request i为进程Pi的请求向量。如果Request i[j] == k,那么进程Pi需要资源类型Rj的实例数量为k。当进程Pi作出资源请求时,采取如下动作:
(1)如果Request i <= Need i,那么转到第(2)步。否则,产生出错条件,这是因为进程Pi已超过了其最大请求。
(2)如果Request i <= Available,那么转到第(3)步。否则,Pi必须等待,这是因为没有可用资源。
(3)假定系统可以分配给进程Pi所请求的资源,并按如下方式修改状态:
Available = Available - Request i;
Allocation i = Allocation i + Request i;
Need i = Need i - Request i;
如果所产生的资源分配状态是安全的(通过上面的安全性算法),那么Pi可分配到它所请求的资源。但是,如果新状态不安全,则进程Pi必须等待Request i并恢复到原来的资源分配状态。