320 likes | 413 Views
两个经典的同步/互斥问题. 生产者与消费者 读者与写者. 生产者 进程. 临界资源. 消费者 进程. 生产者与消费者问题. 模型的抽象化与进程分析( p99). 信号量的设置 Mutex=1 临界资源 Empty=n 空缓冲区的个数 Full=0 满缓冲区的个数. 满. i. j. 空. 图3-8 环形缓冲区. 生产者/消费者算法描述1. var mutex,empty,full:psemaphore; i,j,goods:integer;buffer:array [0 … n-1] of item;
E N D
两个经典的同步/互斥问题 • 生产者与消费者 • 读者与写者
生产者 进程 临界资源 消费者 进程 生产者与消费者问题 • 模型的抽象化与进程分析(p99) • 信号量的设置 Mutex=1 临界资源 Empty=n 空缓冲区的个数 Full=0 满缓冲区的个数
满 i j 空 图3-8 环形缓冲区 生产者/消费者算法描述1 • var mutex,empty,full:psemaphore; • i,j,goods:integer;buffer:array [0…n-1] of item; • procedure producer; 生产者进程 • begin • while true do • begin • produce next product; • P(empty); • P(mutex); • buffer(i):=product; • i:=(i+1) mod(n); • V(mutex); • V(full); • end • end; • procedure consumer; 消费者进程 • begin • while true do • begin • P(full); • P(mutex); • goods:= buffer(j); • j:=(j+1) mod(n); • V(mutex); • V(empty); • consume product; • end • end;
生产者/消费者算法描述2 begin seminitial (mutex.v,1;empty.v,n;full.v,0); i:=j:=0; cobegin producer; consumer; coend end
读者与写者问题 读者 进程 写者 进程 • 模型的抽象化与进程分析(p100) 文件 . . . 写者 进程 读者 进程 • 临界资源: • 读者计数器r-counter • 文件 • 信号量的设置 R-mutex=1 临界资源1 Rw-mutex=1 临界资源2 实例
读者与写者算法描述 var mutex,wrt:psemaphore; readcount:integer; begin seminit(mutex.v,1;wrt.v,1); readcount:= 0; cobegin procedure reader; begin P(mutex); readcount:=readcount+1; if readcount =1 then P(wrt); V(mutex); reading is performing; P(mutex); readcount:=readcount-1; if readcount =0 then V(wrt); V(mutex); end procedure writer; begin P(wrt); writing is performing; V(wrt); end coend end;
第 i 个哲学家活动描述 信号量初值:FORKS[i]=1,其中i=0、1、2、3、4 BEGIN 思考 饥饿 P(FORKS[i mod(5)]) P(FORKS[(i+1)mod(5)]) 吃面条 V(FORKS[i mod(5)]) V(FORKS[(i+1)mod(5)]) END 没有考虑死锁问题
五个哲学家就餐 信号量:c[0]~c[4],初值均为1; 整型变量I=0,1,2,3,4; Philosopher(I) Begin if I mod 2 == 0 then begin P(c[I]); P(c[I+1]mod 5); 吃 V(c[I]); V(c[I+1]mod 5); end else begin P(c[I+1]mod 5); P(c[I]); 吃 V(c[I+1]mod 5); V(c[I]); end End 没有考虑饥饿问题 实例
算法描述 顾客: Begin P(mutex); If (waiting<CHIRS) then Begin Waiting=waiting+1; V(customers); V(mutex); P(barbers); Get_haircut(); End Else Begin V(mutex); End End 信号量:customers=0;barbers=0;mutex=1 整型变量:waiting=0; 理发师: Begin While(true)then Begin P(customers); P(mutex); Waiting=waiting-1; V(barbers); V(mutex); Cut hair(); End End
管程 把分散的各同类临界区集中起来。并为每个可共享资源设立一个专门的机构来统一管理各进程对该资源的访问,这个专门机构称为管程。 Hansen在并发PASCAL语言中首先引入了管程,将它作为语言中的一个并发数据结构类型。 主控程序 … M. Entry1 … M. Entry1 … Monitor M … Entry1 … Entry2 … P(mutext) V(mutext)
管程的组成 管程主要由两部分组成(p102) l局部于该管程的共享数据,这些数据表示了相应资源的状态; l局部于该管程的若干过程,每个过程完成关于上述数据的某种规定操作。 条件变量 每个独立的条件变量是和进程需要等待的某种原因(或说条件)相联系的,当定义一个条件变量时,系统就建立一个相应的等待队列。 关于条件变量有两种操作: wait(x)和signal(x),其中x为条件变量。wait把调用者进程挂在与x相应的等待队列上,signal唤醒相应等待队列上的一个进程。
monitor ringbuffer; var rbuffer:array [0.. n-1] of item; k ,nextempty,nextfull:integer; empty,full:condition; procedureentry put (var product:item); begin if k=n then wait(empty); rbuffer[nextempty]:=product; k:=k+1; nextempty:=(nextempty+1) mod(n); signal(full); end; procedureentry get(var goods:item); begin if k =0 then wait(full); goods:=rbuffer[nextfull]; k:=k-1; nextfull:=(nextfull+1) mod(n); signal(empty); end; begin k := 0; nextempty:=0;nextfull:=0; end; 管程描述 producer: begin repeat produce an item ; ringbuffer.put(item); until false; end consumer: begin repeat ringbuffer.get(item); consume the item; until false end
PCB(B) : mq消息队列 mutex互斥指针 sm同步指针 进程A 进程B : send(B,a) : 发送者:A 长度:5 正文:Hello : receive(b) : 发送者:A 长度:5 正文:Hello b a 接收 发送 图3-9 发送与接收消息过程。 Sender:A Size:5 Text:Hello Nptr 0 消息缓冲 消息系统
Receive 和 send Procedure send(receiver,a) Begin getbuf(a,size,i); i.sender:=a.sender; i.size:=a.size; i.text:=a.text; i.next:=0; getid(PCB,receiver,j); P(j.mutext); insert(j.mq,i); V(j.mutext); V(j.sm); End Procedure receive(b) Begin P(j.sm); P(j.mutext); remove(j.mq,i); V(j.mutext); b.sender:=i.sender; b.size:=i.size; b.text:=i.text; putbuf(i); End
死锁 • 死锁原因和必要条件 • 死锁例子 • 产生死锁的原因和必要条件 • 预防死锁 • 资源独占(静态分配) • 资源顺序分配 • 资源受控动态分配 (避免死锁) • 发现死锁 (死锁检测) • 解除死锁 • 死锁举例
死锁例子 进程P1进程P2 : : 申请文件F 申请磁带机T r1 :申请磁带机T … … r2: 申请文件F 释放磁带机T … 释放文件F 释放文件F …释放磁带机T …
产生死锁的原因和必要条件 • 原因:系统资源不足;进程推进顺序不合适; • 必要条件 • 互斥条件 • 不剥夺条件 • 请求和保持条件 • 环路等待条件
配 请 F 分 P1 P2 求 已 P2 P1 配 请 分 T 求 F T 已 简单的死锁例子 申请不同类型的资源 进程资源图
10 (0) 4 (6) 0 (10) 8 (2) P P P P 0 P P 4 P P 8 Q 7 Q 0 Q 8 Q Q Q Q 7 Q 7 R 6 R 5 R 0 R 6 R 5 R 6 R 7 R 10 (0) 3 (7) 8 (2) 0 (10) 银行家算法 有顾客P、Q、和R,总共需要贷款23个货币单位,银行家有10个货币单位。
死锁检测 检测算法如下: (进程资源图的化简) (1) 把未阻塞(Ci=0)的进程Pi记录在L表中(其全部资源请求已得到满足的进程); (2) 从L表中选择一进程,根据资源分配表S释放分配给该进程的所有资源; (3) 由进程等待表W依次检查和修改需要该进程释放资源的每一个进程的等待计数器Cj; (4) 若Cj=0,则表示该进程所请求的资源已得到满足,不再阻塞,将Pj记入L表中; (5)再从L表中选取另一进程,重复上述操作; (6) 若所有的进程都记入L表中,则系统初始状态为非死锁状态,否则为死锁状态。
p1 r2 p2 r1 r3 表示进程资源图的数据结构 表示请求边:请求矩阵 表示分配遍:分配矩阵 行下标表示进程Pi 列下标表示资源Rj 通过化简进程资源图断定是否存在死锁。
资源 进程 R 1 R2 … Rj … Rm P1 b11 b21 … b1j … bm1 P2 b12 b22 … b2j … bm2 … … … … … … … Pi b1j b2j … bij … bmj … … … … … … … Pm bm1 bm2 … bmj … bmn 请求矩阵Request
R1 R2 … Rj … Rn a11 a12 … a1j … a1n 资源 进程 a21 a22 … a2j … a2n P1 … … … … … … … P2 ai1 ai2 … aij … ain Pi … … … … … … … Pm an1 an2 … amj … amn 分配矩阵Allocation
死锁检测中的数据结构 1、可用资源向量Available:表示m类资源中,每一类的可用数目。 2、请求矩阵Request:是nm 矩阵,表示进程当前对各类资源的请求数目。 3、分配矩阵Allocation:是n m矩阵,用以表示进程某一时刻的资源分配情况。 4、工作向量Work:表示系统可提供给进程继续运行的各类资源数目。 5、进程向量L:记录当前已不占有资源的诸进程。 算法描述
算法描述 Work:=Available; L:={ Li | Allocationi=0 Requesti=0 }; For all LiL do begin for all Requesti Work begin Work= Work+Allocationi LiL end end deadlock:=(L={P1,P2,…,Pn}
解除死锁 • 撤销死锁中的进程,释放出资源。 • 撤销进程的代价 • 进程优先级 • 进程运行代价(已运行的%) • 进程类型 等等