【操作系统】知识点总结 之 并发进程

1.并发进程


1.1顺序进程与并发进程

顺序进程

概念:略

特征:顺序性执行、封闭性,独占资源、确定性,即可再现性。


并发进程:

并发环境: 在一定时间内物理机器上有两个或两个以上的程序同处于开始运行但尚未结束的状态,并且次序不是事先确定的

特征:

(1)程序结果的不可再现性并发程序执行的结果与其执行的相对速度有关,是不确定的(2)在并发环境下程序的执行是间断性的执行——停——执行
(3)资源共享   系统中资源被多个进程使用
(4)独立性和制约性 独立的相对速度、起始时间   进程之间可相互作用(相互制约) 可分为直接作用和间接作用
(5)程序和计算不再一一对应
(6)并发性


1.2与时间有关的错误

1、并发进程交替使用共享资源时可能出现的错误:例如:P1和P2是两个并发进程P1: ①R1=C; ②R1=R1+1;③C=R1;P2: ④R2=C;⑤R2=R2+1;⑥C=R2;P1全部执行完毕后再执行P2,则C增加2若P2中的④在P1中的③之前执行,则C增加1
原因是没有正确地控制对共享变量C的访问。

2、飞机订票问题

3、缓冲区读写问题:get、copy、put是3个并发进程


1.3 进程间的联系

1、间接式与直接式制约
直接式制约:一程序段等待另一程序段的执行结果
间接式制约:并发程序段竞争同一资源
2、相交进程与无关进程:
相交进程:并发进程在逻辑上有某种联系
无关进程:逻辑上无任何联系的并发进程
直接作用只发生在相交进程之间;间接作用可以发生在相交进程之间,也可发生在无关进程之间

3、进程的同步与互斥:

进程同步(直接作用):根据一定的时序关系合作完成一项任务并发进程因直接制约而互相等待,彼此相互发送消息进行合作,使得各进程按一定的速度执行进程间的相互联系是有意识的安排的,直接作用只发生在相交进程间。例子:司机与售票员。

进程互斥(间接作用):各进程竞争使用临界资源(一次只允许一个进程使用的系统资源)。进程互斥是进程同步的一种特殊情况。进程间要通过某种中介发生联系,是无意识安排的,可发生在相交进程之间,也可发生在无关进程之间。


2.临界区管理


2.1 临界区及其使用原则

临界区:进程中涉及临近资源的程序段为临界区/互斥区,多个进程的临界区为相关临界区。

使用原则:有空让进、无空等待、多中择一、有限等待、让权等待。

解决进程互斥的两种做法:由竞争各方平等协商解决,包括硬件、软件两类方法。引入进程管理者来协调竞争各方对互斥资源的使用 。

2.2 实现临界区管理的软件方法

两个失败的尝试1:

bool inside1=false; bool inside2=false;
cobegin
process P1 process P2
while(inside2) do    while(inside1) do
begin end; begin end;
inside1:=true;   inside2 :=true;
临界区;    临界区;
inside1=false;   inside2=false;
} }
coend


两个失败的尝试2:

bool inside1:=false; bool inside2:=false;
cobegin
process P1 process P2
begin begin
inside1:=true;   inside2=true;
while(inside2) do    while(inside1) do
begin end; begin end;
临界区;    临界区;
inside1:=false;   inside2:=false;
end end
coend

成功解决方法(Dekker算法):

详见:http://blog.csdn.net/aiwuzhiling/article/details/38824029

2.3 实现临界区管理的硬件方法

通过专门提供的硬件指令管理临界区:测试并建立指令TS、交换指令SWAP、开关中断指令

软件解法的缺点主要在于:
   1. 忙等待
   2. 实现过于复杂,需要高的编程技巧

硬件方法解决临界区的管理较为简单有效,其缺点主要在于:
会导致“忙等待”
会导致“饥饿”
中断屏蔽方法代价较高,不适应多处理器


3、信号量与P、V操作


3.1信号量的定义

提出:以上介绍的各种算法都存在问题,它们是平等进程间的一种协商机制,需要一个地位高于进程的管理者来解决公有资源的使用问题,操作系统可从进程管理者的角度来处理互斥的问题,信号量就是操作系统提供的管理公有资源的有效手段。

定义:Struct semaphore 
         {    int value; //信号量的值
              pointer_PCB queue; //信号量队列指针
         } 

信号量说明:semaphore s信号量代表对某种公共资源的管理(如停车场的看门人),其值是一个非负整数(如停车场内的车位数)
要使用资源的进程(如要进入停车场的车)需通过信号量,有资源时顺利通过(有车位时,看门人打开车栏);若没有资源可用(如空车位为0),则所有进程都将进入对应信号量的等待队列(如车子在看门人看守的车栏外排队等待)
当一个进程归还资源(如车开出停车场)时,此时若信号量队列有等待进程则释放一个(如让一辆车进入停车场)

特性:

(1)信号量代表对某种公共资源的管理(如停车场的看门人),其值是一个非负整数(如停车场内的车位数)。
(2)要使用资源的进程(如要进入停车场的车)需通过信号量,有资源时顺利通过(有车位时,看门人打开车栏);若没有资源可用(如空车位为0),则所有进程都将进入对应信号量的等待队列(如车子在看门人看守的车栏外排队等待)。
(3)当一个进程归还资源(如车开出停车场)时,此时若信号量队列有等待进程则释放一个(如让一辆车进入停车场)。

3.2 P、V操作定义

P操作用于申请信号量管理的资源(如停车场一例中需要进入停车场使用车位的车就应执行P操作)

V操作用于释放资源(如停车场一例中需要开出停车场归还车位的车就应执行V操作)

P操作:

P(s)
{
  s.value = s.value-- ; //s.value减1
  if (s.value < 0)
//该进程被阻塞,进入相应队列,然后转进程调度 
   {
     该进程状态置为等待状态;
     将该进程的PCB插入相应的等待队列s.queue的末尾;
   }
   //若s.value减1后仍大于或等于零,则进程继续执行
}

V操作:

V(s)
{
  s.value = s.value ++; //s.value加1
  if (s.value < = 0)
   //从队列中唤醒一等待进程,然后继续执行或转进程调度 
   {
    唤醒相应等待队列s.queue中等待的一个进程;
    改变其状态为就绪态,并将其插入就绪队列;
     } 
  //若相加结果大于零,则进程继续执行 
}

3.3 信号量的使用

(1)使用注意事项:必须置一次且只能置一次初值,且初值不能为负数;只能执行P、V操作 
用信号量及P、V操作解决进程间互斥问题 。

(2)用信号量及P、V操作解决进程间互斥问题 :
mutex : semaphore; mutex:= 1;
cobegin 
 process Pi
           begin
               …
               P(mutex); 

临界区;

               V(mutex);
               …
           end; 
coend; 


用信号量及P、V操作解决单类机票问题:

var A : ARRAY[1..m] OF integer;
mutex : semaphore;  mutex:= 1;
cobegin 
process Pi
     var Xi:integer;
begin
     L1:
      按旅客要求找到A[j];
      P(mutex)
      Xi := A[j];

      if  Xi>=1 
           then begin Xi:=Xi-1; A[j]:=Xi; 
                V(mutex);输出一张票;  end;
           else  begin 
           V(mutex);输出票已售完; end;
     goto L1;
     end; 

Coend 


用信号量及P、V操作解决多类机票问题
var A : ARRAY[1..m] OF integer;
      s : ARRAY[1..m] OF semaphore; s[j] := 1;
cobegin 

process Pi
     var Xi:integer;
begin
     L1:
      按旅客要求找到A[j];
      P(mutex)
      Xi := A[j];

     if  Xi>=1 
 
   then begin Xi:=Xi-1; A[j]:=Xi; 
       V(mutex);输出一张票;  end;
   
  else  begin 
       V(mutex);输出票已售完; end;
     goto L1;
 
    end; 
Coend 

(3)用信号量及P、V操作解决进程间同步问题 

生产者-消费者问题

问题描述:生产者往缓冲区中放产品,消费者从缓冲区中取产品。

生产者P进程不能往“满”的缓冲区中放产品,设置信号量为S1,初值为1,代表缓冲区有1个空闲空间。

消费者Q进程不能从“空”的缓冲区中取产品,设置信号量S2 ,初值为0,代表缓冲区有0个产品。


用信号量及P、V操作解决进程间同并不斥问题

P //生产者进程
while  (true)  {
      生产一个产品;
      P(s1) ; //初值为1
      送产品到缓冲区;
      V(s2);
}; 

C //消费者进程
while  (true)  {
     P(s2); //初值为0
           从缓冲区取产品;
    V(s1);
             消费产品;
}; 

3.4 信号量及P、V操作讨论

信号量及P、V操作的物理含义
① S>0表示有S个资源可用
② S=0表示无资源可用
③ S<0则| S |表示S等待队列中的进程个数
④ P(S)表示申请一个资源
⑤ V(S)表示释放一个资源 

P、V操作必须成对出现,有一个P操作就一定有一个V操作
① 当为互斥操作时,它们处于同一进程
② 当为同步操作时,则不在同一进程中出现
③ 如果P(S1)和P(S2)两个操作在一起,那么P操作的顺序至关重要,一个同步P操作与一个互斥P操作在一起时,同步P操作在互斥P操作前,而两个V操作无关紧要

信号量及P、V的优缺点
① 优点:简单且表达能力强,用P、V操作可解决任何同步、互斥问题
② 缺点:不够安全,P、V操作使用不当会出现死锁;遇到复杂同步互斥问题时实现复杂


3.5  信号量与P、V操作经典问题

(1)哲学家吃通心面问题:

问题描述:5个哲学家围坐在一圆桌旁,桌中央有一盘通心面,每人面前有一只空盘于,每两人之间放一把叉子。每个哲学家思考、饥饿、然后吃通心面。每个哲学家必须直接从自己左边和右边同时获得两把叉子才能吃面
解决思路:5位哲学家看作5个进程,需要互斥使用5把叉子,这5把叉子是共享资源,用5个信号量表示。

var fork[I]:array[0..4] of semaphore;       fork[i] := 1;
cobegin 
process Pi                    // i=0,1,2,3,4,
    begin
     L1: 思考;
     P(fork[i]);             //叉子逆时针编号,先拿左边叉子
     P(fork[(i+1)mod 5]);         //再拿右边叉子
     吃通心面;
     V(fork[i]); //归还左边叉子
     V(fork[(i+1)mod 5]); //归还右边叉子
     goto L1;
    end; 
coend 

上述解法保证了对叉子的互斥使用,但可能出现每位哲学家均拿起左边叉子而同时又等待拿右边叉子的情况,发生死锁,可通过下列几种办法避免死锁:
至多允许4个哲学家同时吃
奇数号先取左手边的叉子,偶数号先取右手边的叉子
每个哲学家取到手边的两把叉子才吃,否则一把叉子也不取 

(2)生产者消费者问题

问题描述:若干进程通过K个有限共享缓冲区交换数据。其中,“生产者”进程不断写入,而“消费者”进程不断读出。任何时刻只能有一个进程可对共享缓冲区进行操作。且满足条件:① 消费者想接收数据时,有界缓冲区中至少有一个单元是满的;② 生产者想发送数据时,有界缓冲区中至少有一个单元是空的 。

解决思路:设置3个信号量
full表示“满”数目,即缓冲区当前产品数,初值为0 
empty表示缓冲区“空位”数目,初值为K;full + empty == K 
mutex用于访问缓冲区时的互斥,初值是1 。

var B: array[0..k-1] of item; in, out:integer:= 0; //缓冲区读写指针
empty, full, mutex: semaphore; empty:=k; full:=0; mutex:=1; 
cobegin 
process producer_i
begin
     L1:produce a product;
     P(empty);P(mutex);//empty初始为K,表示缓冲区有K个空位,每生产一个p(empty)让空位资源-1,<0,将生产进程进等待队列
     B[in] := product;
     In:=(in+1) mod k;
     V(mutex);  V(full);//full表示目前缓冲区有多少个产品,缓冲区full信号量+1,加入一个产品
     Goto L1;
     end;

process consumer_j        
begin
   L2: P(full);  P(mutex);//
        Product:= B[out];//将缓冲区产品数-1
        out:=(out+1) mod k;
        V(mutex);      V(empty);//空位+1
        Consume a product;
        Goto L2;
      end;  

coend 

(3)苹果桔子问题

问题描述:桌上有一只盘子,每次只能放入一只水果;爸爸专向盘子中放苹果(apple),妈妈专向盘子中放桔于(orange);一个儿子专等吃盘子中的桔子,一个女儿专等吃盘子里的苹果
解决思路:生产者消费者问题的变形,有两类生产者和两类消费者,仍然设置3个信号量
sp表示盘子能放的水果数目,初值为1
sg1表示盘子里有无桔子,初值为0 
Sg2表示盘子里有无苹果,初值为0 

sp, sg1, sg2: semaphore; sp := 1; sg1, := 0; sg2 := 0;
cobegin 
process father        
begin
     L1:削一个苹果;
     P(sp); 放苹果;
V(sg2);goto L1;
end; 
process mother        
begin
     L2:剥一个桔子;
     P(sp); 放桔子;
     V(sg1); goto L2;
end; 

process daughter       
begin
     L4: P(sg2);取苹果;
     V(sp); 吃苹果;
     goto L4;
end; 
process son        
begin
     L3: P(sg1); 取桔子;
     V(sp); 吃桔子;
     goto L3;
end; 
coend 

(4)读者和写者问题

问题描述:读者和写者两组并发进程共享一个文件F,要求允许多个读者同时执行读操作,任一写者在完成写操作之前不允许其他读者或写者工作,写者执行写操作前,应让已有的写者和读者全部退出 
解决思路:设置2个信号量W和R,1个控制变量rc
W控制读写进程对文件的互斥访问,初值为1
R控制各个读进程对rc的互斥访问,初值为1
rc记录正在读文件的进程数,初值为0

var rc: integer; rc:=0; W,R: semaphore; W := 1;  R := 1; 
cobegin 
procedure read;
begin
  P(R);
  rc := rc + 1;
  if rc=1 then P(W);
  V(R);
  读文件;
  P(R);
  rc := rc - 1;
  if rc = 0 then V(W);
  V(R);
end; 

procedure write;
begin
    P(W);
    写文件;
    V(W);
end; 
coend 

读写问题详见:http://blog.csdn.net/aiwuzhiling/article/details/38846619

(5)理发师问题

问题描述:理发店有一位理发师、一把理发椅和n把供等候理发的顾客坐的椅子。没顾客时理发师在理发椅上睡觉,顾客来时必须叫醒理发师,如果其正在理发则坐下来等待,没有空椅子坐就离开
解决思路:设置1个控制变量waiting 和3个信号量
waiting记录等候理发的顾客数,初值为0
customers表等候理发的顾客数,可阻塞理发师进程,初值为0
barbers表正在等候顾客的理发师数,可阻塞顾客进程,初值为0
mutex用于互斥修改waiting,初值为1

解答详见:http://blog.csdn.net/aiwuzhiling/article/details/38848957

3.6 POSIX信号量 略

POSIX 有两种信号量的实现机制:
无名信号量:可以用在共享内存的情况下,如实现进程中各个线程之间的互斥和同步
命名信号量:通常用于不共享内存的情况下,如不共享内存的进程之间 
本节所介绍的函数和数据结构需要引用头文件semaphore.h。

3.7  Linux中的信号量机制 略

Linux中的基本信号量机制
Linux内核的信号量在概念和原理上和用户态的System V的IPC机制信号量相同,但它绝不可能在内核外使用 
只有一个持有者的信号量叫二值信号量或互斥信号量
允许有多个持有者的信号量叫计数信号量,在初始化时要说明最多允许有多少个持有者(Count值) 
当任务访问完被信号量保护的共享资源后,必须释放信号量,释放信号量通过把信号量的值加1实现,假如信号量的值为非正数,表明有任务等待当前信号量,因此它也唤醒任何等待该信号量的任务 


4、进程间通信


4.1概念

进程间通信(Inter-Process Communication/IPC ):进程之间互相交换信息的工作。

进程间的通信根据通信的内容可以划分为两种
控制信息的传送:只传递简单的信号,不能传递交换大量信息,如信号量机制及P、V操作(低级通信原语)控制的进程同步和互斥
大批量数据传送:Send/Receive原语(高级通信原语)

4.2通信方式

主从式(Master-Servant)通信:主进程-从进程
主进程可自由地使用从进程的资源或数据
从进程的动作受主进程的控制
主进程和从进程关系固定
典型例子是终端控制进程和终端进程


会话式(Dialogue)通信:使用进程-服务进程
使用进程调用服务进程提供的服务
使用进程在使用服务进程所提供的服务之前,必须得到服务进程的许可
服务进程根据使用进程的要求提供服务,但对所提供服务的控制由服务进程自身完成
使用进程和服务进程在进行通信时有固定连接关系


消息队列或邮箱(Message Queue or Mailbox):发送进程-接收进程
消息用于表示所交换的数据,传递大量信息之外,还意味着两个互相通信的进程地位平等
缓冲区或邮箱专门存放被传送消息
只要存在空缓冲区或邮箱,无论接收进程是否已准备好接收消息,发送进程都将把所要发送的消息送入缓冲区队列或邮箱
发送进程相接收进程之间无直接连接关系

共享存储区(Shared Memory): 读进程-写进程
两个需要互相交换信息的进程通过对同一共享数据区的操作来达到互相通信的目的
不要求数据移动


上述方式可以分为如下两类:
直接通信:信息直接传递给接收方
在发送时,指定接收方的地址或标识,也可以指定多个接收方或广播式地址
在接收时,允许接收来自任意发送方的消息,并在读出消息的同时获取发送方的地址
接收方可接收来自任意发送方的消息,并在读出消息的同时获取发送方的地址


间接通信:借助于收发双方进程之外的共享数据结构作为通信中转
如消息队列或是信箱
接收方和发送方的数目可以是任意的

 

通信过程中的其他特征

通信链路特征
链路是点对点还是广播链路
通信链路是否带缓冲区
链路是单向还是双向等


数据格式
字节流格式:接收方不保留各次发送之间的分界
报文格式:接收方保留各次发送之间的分界。报文方式还可进一步分成定长报文/不定长报文和可靠报文/不可靠报文
收发操作的同步方式
阻塞操作:指操作方要等待操作结束
不阻塞操作:指操作提交后立即返回


4.3Linux中的进程间通信机制

(1)信号通信机制
每个信号都对应一个正整数常量(即信号编号 signal number),代表同一用户的诸进程之间传送事先约定的信息的类型,用于通知某进程发生了某异常事件 
每个进程在运行时,都要通过信号机制来检查是否有信号到达。若有,便中断正在执行的程序,转向与该信号相对应的处理程序;处理结束后再返回到原来的断点继续执行
信号机制是对中断机制的一种模拟,又称为软中断 


信号与中断的相似点主要包括:
① 相同异步通信方式
② 检测出有信号或中断请求时,都暂停正在执行的程序而转去执行相应的处理程序
③ 处理完毕后返回到原来的断点
④ 对信号或中断都可进行屏蔽


信号与中断的区别主要包括:
①信号没有优先级,所有的信号都平等;而中断有优先级
② 信号处理程序在用户态下运行;而中断处理程序是在核心态下运行;
③信号响应通常都有较大的时间延迟;而中断响应是及时的


信号机制的基本功能
发送信号:由发送进程把信号送到指定进程的信号域的某一位上
预置对信号的处理方式,一般有忽略、退出、执行预知程序三种方式
收受信号的进程按事先的规定完成对相应事件的处理 


(2)共享存储区机制

通信速度最高的一种通信机制 
共享存储区为内存中的某一个区域,映射在若干需通过该区域通信的进程的虚地址空间中 
一个进程的虚地址空间中可以连接多个共享存储区 

进程间欲利用共享存储区进行通信时,必须先在内存中建立一共享存储区,然后将它附接到自己的虚地址空间上。此后,进程对该区的访问操作,与对其虚地址空间的其他部分的操作完全相同,通过对共享存储区中数据的读、写来进行直接通信
共享存储区机制并未提供对该区进行互斥访问及进程同步的措施。因而当用户需要使用该机制时,必须自己设置同步和互斥措施才能保证实现正确的通信


(3)消息通信机制

消息是一个格式化的可变长的信息单元
消息通信机制允许由一个进程给其他任意的进程发送一个消息
当一个进程收到多个消息时,可将它们排成一个消息队列
每一个消息队列都有一个称为关键字(key)的名字,即消息队列描述符,由用户指定,其作用与用户文件描述符一样,是为了方便用户和系统对消息队列的访问  

共享存储区和消息通信机制的比较
① 建立:消息队列的建立消耗资源更少,它只是一个软件上设定的问题;而共享区需要对硬件操作,实现内存的映像,控制起来更复杂。如果每次都重新进行队列或共享的建立,共享区的设立没有什么优势
② 使用:共享区的数据传输受到系统硬件的支持,不耗费多余的资源。而消息传递由软件进行控制和实现,需要消耗一定的cpu的资源。从这个意义上讲,共享区更适合频繁和大量的数据传输
③ 同步:消息的传递自身就带有同步控制。而共享队列如果不借助其他机制进行同步,接收数据的一方必须进行不断地查询,浪费CPU资源。可见消息方式的使用更加灵活 


(4)管道通信机制
管道:能够连接一个写进程和一个读进程的、并允许它们以生产者—消费者方式进行通信的一个共享文件,又称为pipe文件
由写进程从管道的写入端(句柄1)将数 据写入管道,而读进程则从管道的读出端 (句柄0)读出数据 


5、死锁


5.1基本概念

定义:操作系统中多道进程的并发执行可以改善系统的资源利用率,但也可能出现若干进程都相互等待对方释放资源才能继续运行,否则就阻塞的情况。

死锁:系统中两个或者多个进程无限期地等待永远不会发生的条件,系统处于停滞状态,这种现象称为进程死锁,这一组进程就称为死锁进程 。

例子:

申请不同资源


申请同类资源

内存资源有m个分配单位,n个进程共享,每个进程依次只能申请一个单位,满足总量才能使用,使用完后一次性释放

m=2
n=3

产生原因:

系统资源不足:如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁 
进程运行推进的顺序不合适:如上面打印机和扫描仪申请一例
资源分配不当:如上面内存分配一例

产生死锁的4个必要条件

互斥使用(资源独占):一个资源每次只能给一个进程使用
不可强占(不可剥夺):资源申请者不能强行地从资源占有者手中夺取资源,资源只能由占有者自愿释放
请求和保持(部分分配,占有申请):一个进程在申请新的资源的同时保持对原有资源的占有(只有这样才是动态申请,动态分配)
循环等待:存在一个进程等待队列 {P1 , P2 , … , Pn},其中P1等待P2占有的资源,P2等待P3占有的资源,…,Pn等待P1占有的资源,形成一个进程等待环路 


5.2死锁的预防——解决死锁的静态方法

基本策略
在系统设计时确定资源分配算法,保证不发生死锁
通过破坏产生死锁的4个必要条件之一来实现
由于系统存在很多独占资源,破坏“互斥使用”这一必要条件不太现实,重点探讨破坏后3种必要条件的方法 

破坏“不可剥夺”条件
在允许进程动态申请资源前提下规定,一个进程在申请新的资源不能立即得到满足而变为等待状态之前,必须释放已占有的全部资源,若需要再重新申请

破坏“请求和保持”条件
要求每个进程在运行前必须一次性申请它所要求的所有资源,且仅当该进程所要资源均可满足时才给予一次性分配

破坏“循环等待”条件
采用资源有序分配法,把系统中所有资源编号,进程在申请资源时必须严格按资源编号的递增次序进行,否则操作系统不予分配

5.3死锁的避免——解决死锁的动态方法

基本策略
在系统运行过程中,对进程发出的每一个系统能够满足的资源申请进行动态检查,并根据检查结果决定是否分配资源,若分配后系统可能发生死锁,则不予分配,否则予以分配 
关键在于区分安全状态与不安全状态,安全状态一定没有死锁发生,因而对进程的申请进行试分配,分配后系统状态为安全状态则满足, 否则不满足

一个典型的死锁避免算法:银行家算法

① 银行家拥有一笔周转资金
② 客户要求分期贷款,如果客户能够得到各期贷款,就一定能够归还贷款,否则就一定不能归还贷款
③ 银行家应谨慎地贷款,防止出现坏账
④ 银行家采用的具体方法是看他是否有足够的剩余资金满足某一个需求的客户,如此反复下去
⑤ 如果所有投资最终都被收回,则该状态是安全的,最初的请求可以批准

用银行家算法避免死锁:
操作系统(银行家)
操作系统管理的资源(周转资金)
进程(要求贷款的客户)


银行家算法思想在单种资源情况下的应用:(4个客户每个都有一个贷款额度)

一个状态被称为是安全状态

条件是存在一个状态序列能够使所有的客户均得到其所有的贷款。
图示b状态是安全的,以使Marvin运行结束,释放所有的4个单位资金。这样下去便可满足Suzanna或Barbara的请求。


一个状态被称为是不安全状态

考虑给Barbara另一个她申请的资源,则得到的状态是不安全的。
如果忽然所有的客户都申请,希望得到最大贷款额,而银行家无法满足其中任何一个的要求,则发生死锁。 


对进程的每个针对该资源的申请进行检查,若会导致不安全状态,则不满足该申请;否则便满足 
安全状态的具体定义:
安全序列:如果对一个进程序列P1,…,Pn中的每一个进程Pi(1≤i≤n),它以后尚需要的资源量不超过系统当前剩余资源量与所有进程Pj (j < i )当前占有资源量之和, 则该序列为安全序列
安全状态:如果系统中的所有进程能够排成一个安全序列,则系统处于安全状态

例1:一个共有150个存储单元的系统,分配给3个进程,P1最大需求70,己占有25;P2最大需求60,己占有40;P3最大需求60,己占有45
资源申请:P4进程到达,最大需求60,最初请求25个
试分配:由于系统目前还有150-25-40-45=40个单元,P4进程到达,若满足其申请,则系统还余15个单元
分析此时系统状态(寻找安全序列):可以将15个单元分给P3,它执行完后会释放60个单元,可供P1(还要45个单元),P2(还要20个单元),P4(还要35个单元)任何一个执行。存在 P3P1P2P4等6种安全序列
决定是否满足申请:预分配后系统仍处于安全状态,因而可以满足P4的资源申请

例2:一个共有150个存储单元的系统,分配给3个进程,P1最大需求70,己占有25;P2最大需求60,己占有40;P3最大需求60,己占有45
资源申请:P4进程到达,最大需求60,最初请求35
试分配:由于系统目前还有150-25-40-45=40个单元,P4进程到达,若满足其申请,则系统还余5个单元
分析此时系统状态(寻找安全序列):不能满足任何一个进程需求,找不到安全序列
决定是否满足申请:预分配后系统进入不安全状态,因而不能满足P4的资源申请


银行家算法思想在多种资源情况下的应用:

总的资源E、已分配资源P、剩余资源A 


算法描述

查找右边矩阵是否有一行,其未被满足的设备数均小于或等于向量A。如果找不到,系统将死锁,任何进程都无法运行结束

若找到这样一行,可以假设它获得所需的资源并运行结束,将该进程标记为结束,并将资源加到向量A上
重复以上两步,直到所有进程都标记为结束,则状态是安全的,否则将发生死锁 

系统有n个进程和m种不同类型的资源,相关定义如下:

各类资源总数向量——Resource=(R1,R2,…,Rm),其中Ri表示第i类资源总数
各类资源未分配数向量——Available=(V1,V2,…,Vm) 
最大需求矩阵——Cij表示进程Pi对Rj类资源的最大需求量
分配矩阵——Aij表示进程Pi已分到Rj类资源的个数 


算法基本思想
①系统中所有进程进入进程集合;在安全状态下系统收到进程的资源请求后进行试分配(修改Available )
②将系统剩余资源和进程集合中其他进程还需要的资源数作比较,找出能满足最大需求量的进程Pi (即(Ci1,…Cim) -(Ai1,…Aim) ≤ Available),找不到则转④ 
③把进程Pi从集合中去掉,将其占用资源归还给系统(即Available+=(Ai1,…Aim));集合为空转④,否则转②
④检查进程集合,若为空表明本次申请执行后系统仍处于安全状态,可实施分配;否则说明该申请将导致系统处于不安全状态,则暂不实施分配,让申请进程等待 

例:系统状态如下图所示,给出了剩余资源Available、最大需求矩阵C、分配矩阵A的情况,试处理进程P1发出的资源请求(1, 0, 0, 0)



试分配后,Available=(0, 6, 2, 2)



P0符合条件,归还资源后,Available=(0, 6, 2, 2)+(0, 0, 3, 2)=(0, 6, 5, 4)



P3符合条件,归还资源后,Available=(0, 6, 5, 4)+(0, 3, 3, 2)=(0, 9, 8, 6)



P1和P4都符合条件,选P1归还资源,Available =(0, 9, 8, 6)+(2, 0, 0, 0)=(2, 9, 8, 6)



此时剩余进程都符合条件,找到安全序列P0, P3, P1, P2, P4;P0, P3, P1, P4, P2;P0, P3, P4, P1, P2(可见安全序列不一定唯一)。试分配后系统仍安全,可满足请求



5.4 死锁的检测及解除

基本策略
允许死锁发生
操作系统不断监视系统进展情况,判断死锁是否发生
一旦死锁发生则采取专门的措施,解除死锁并以最小的代价恢复操作系统运行


死锁检测

检测时机:进程等待时、定时检测、资源利用率下降时
检测手段:利用进程-资源分配图 

方框表示资源类(资源的不同类型)
方框中的黑圆点表示资源实例(存在于每个资源类中)
圆圈中加进程名表示进程
资源实例指向进程的一条有向边来表示分配边
进程指向资源类的一条有向边来表示申请边


进程-资源分配图中的死锁判断
无环路,则此时系统没有发生死锁
有环路,且每个资源类中仅有一个资源,则系统中发生了死锁。此时,环路是系统发生死锁的充要条件,环路中的进程便为死锁进程 
有环路,且涉及的资源类中有多个资源,则环路的存在只是产生死锁的必要条件而不是充分条件


检测思路:检测“进程-资源分配图”是否可完全简化(能经过一系列简化使所有进程成为孤立结点,则该图是可完全简化的;否则则称该图是不可完全简化的)


死锁解除:应以最小的代价恢复系统的运行

资源剥夺法:当发现死锁后,从其他进程那里剥夺足够数量的资源给死锁进程,以解除死锁状态;

撤消进程法:
撤消全部死锁进程,使系统恢复到正常状态。最简单但代价太大
按照某种顺序逐个撤消死锁进程,直到有足够的资源供其他未被撤消的进程使用,消除死锁状态为止


6、管程

信号量的大量同步操作分散在各个进程中不便于管理和控制,读写和维护都很困难,还有可能导致系统死锁 
Dijkstra于1971年提出把所有进程对某一种临界资源的同步操作都集中起来,构成一个所谓的秘书进程(即管程)
凡要访问该临界资源的进程,都需先报告秘书,由秘书来实现诸进程对同一临界资源的互斥使用

概念:

一个管程定义了一个数据结构和能为并发进程所执行(在该数据结构上)的一组操作,这组操作能同步进程和改变管程中的数据 ——Hanson
管程用共享数据结构抽象地表示系统中的共享资源,而把对该共享数据结构实施的操作定义为一组过程,集中在一个模块中。操作系统或并发程序就由这样的模块构成,模块之间联系清晰,便于维护和修改,易于保证正确性 


管程的特性:

模块化:管程是一个基本程序单位,可以单独编译
抽象数据类型:管程中不仅有数据,而且有对数据的操作
信息掩蔽:管程外可以调用管程内部定义的一些函数,但函数的具体实现外部不可见 


管程的使用:

管程相当于围墙,将共享变量和对它进行操作的若干个过程围了起来
任何进程要访问临界资源时,都必须进入管程通过调用其内的某个函数进行申请
任何进程要归还资源时,也必须进入管程通过调用其内的某个函数进行归还
进程必须互斥访问管程,即同一时刻只能有一个进程在调用管程内的某个函数

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: #!/bin/bash# 设置并发进程的最大数量 MAX_PROCESSES=4# 启动4个后台进程 for i in `seq 1 $MAX_PROCESSES`; do # 在后台运行脚本 ./script.sh & done# 等待所有进程结束 wait ### 回答2: 并发进程是指多个进程同时执行,可以提高系统的效率和资源利用率。要编写一个并发进程的shell脚本,可以使用以下方法: ```shell #!/bin/bash # 并发进程的shell脚本 # 定义并发进程数量 NUM_PROCESSES=3 # 定义要执行的任务函数 task() { echo "开始执行任务 $1" sleep 5 # 模拟任务执行时间 echo "任务 $1 执行完毕" } # 循环创建并发进程进行任务执行 for ((i=1; i<=NUM_PROCESSES; i++)) do task $i & # 后台执行任务函数 done # 等待所有后台任务执行完毕 wait echo "所有任务已执行完毕" ``` 在上述脚本中,首先定义了并发进程的数量为NUM_PROCESSES,可以根据实际情况进行调整。 然后,定义了一个名为task的函数,用于执行具体的任务。在示例中,任务函数会打印出执行的任务编号,然后通过sleep命令模拟任务的执行时间。 接下来,使用循环创建了NUM_PROCESSES个后台进程,每个进程都会调用task函数进行任务执行。 最后,使用wait命令等待所有后台进程执行完毕,然后输出"所有任务已执行完毕"的信息。 使用这个脚本可以实现多个任务的并发执行,提高了系统的效率和资源利用率。 ### 回答3: 并发进程是指多个进程同时执行的情况。在shell脚本中,我们可以利用后台执行和等待命令实现并发进程的效果。 以下是一个简单的示例: 脚本名称:concurrent_processes.sh ```shell #!/bin/bash # 定义并发进程数量 concurrent_count=3 # 循环执行并发进程逻辑 for ((i=1; i<=$concurrent_count; i++)) do { # 执行需要并发的命令 echo "并发进程$i 开始执行" # 假设这里是需要执行的命令,比如:command1、command2等 sleep 5 echo "并发进程$i 执行完毕" } & done # 等待所有并发进程执行完毕 wait # 所有并发进程执行完毕后的逻辑 echo "所有并发进程执行完毕" ``` 说明: 1. 将上述脚本保存为concurrent_processes.sh,并赋予执行权限(chmod +x concurrent_processes.sh)。 2. 脚本中的concurrent_count变量定义了并发进程的数量,这里设置为3。 3. 在for循环中,我们使用了后台执行命令(&),并在大括号内执行需要并发的命令逻辑。这里使用了sleep 5来模拟需要执行的命令。 4. 在循环结束后,使用wait命令等待所有并发进程执行完毕。 5. 最后输出"所有并发进程执行完毕"的提示信息。 执行该脚本后,会同时启动3个并发进程执行相同的逻辑(这里是sleep 5)。待所有进程执行完毕后,输出最终提示信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值