操作系统课件:第6章 进程同步_第1页
操作系统课件:第6章 进程同步_第2页
操作系统课件:第6章 进程同步_第3页
操作系统课件:第6章 进程同步_第4页
操作系统课件:第6章 进程同步_第5页
已阅读5页,还剩61页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Chap6进程同步内容背景临界区问题信号量经典同步问题管程同步实例原子事务总结背景对共享数据的并发访问可能导致数据的不一致性.要保持数据的一致性,就需要一种保证并发进程的正确执行顺序的机制.[第4章中]解决有界缓冲区问题的共享内存方法在同一时刻最多允许存放n-1个产品,所有n个缓冲区都被使用的解法不是简单的。假设通过增加一个变量counter来修改这一算法,初始化为0,每次向缓冲区增加一个新项时,counter递增;每次从缓冲区中移去一项时,counter递减。Shareddata

#defineBUFFER_SIZE10typedefstruct{ ...}item;itembuffer[BUFFER_SIZE];intin=0;intout=0;intcounter=0;有界缓冲区生产者进程 itemnextProduced;

while(1){ while(counter==BUFFER_SIZE) ;/*donothing*/ buffer[in]=nextProduced; in=(in+1)%BUFFER_SIZE; counter++; }有界缓冲区enter()消费者进程 itemnextConsumed;

while(1){ while(counter==0) ;/*donothing*/ nextConsumed=buffer[out]; out=(out+1)%BUFFER_SIZE; counter--; }

有界缓冲区remove()下列语句必须被原子性地执行

counter++;

counter--;

原子操作意味着一个操作在整个执行期间没有中断。有界缓冲区语句“count++”可按如下方式以机器语言实现:

register1=counter register1=register1+1

counter=register1

语句“count--”可按如下方式来实现:

register2=counter

register2=register2–1

counter=register2有界缓冲区如果生产者和消费者试图并发地更新缓冲区,汇编语言语句可能交叉执行。交叉取决于生产者和消费者进程是如何被调度的。有界缓冲区假设counter初值为5.一种语句的交叉形式如下:

producer:register1=counter(register1=5)

producer:register1=register1+1(register1=6)

consumer:register2=counter(register2=5)

consumer:register2=register2–1(register2=4)

producer:counter=register1(counter=6)

consumer:counter=register2(counter=4)

count

的值可以是4或6,而正确结果应是5。有界缓冲区竞争条件:多个进程并发访问和操作同一数据的情况。共享数据的最终结果取决于最后操作的进程。为了防止上述竞争条件,并发进程必须同步。竞争条件RaceCondition临界资源和临界区criticalresource(临界资源)系统中某些资源一次只允许一个进程使用,称这样的资源为临界资源或互斥资源或共享变量。Critical-Section(临界区)涉及到临界资源的代码段叫临界区。解决临界区问题1. 互斥(MutualExclusion

)。假定进程Pi在其临界区内执行,其他任何进程将被排斥在自己的临界区之外.2. 有空让进(Progress)。临界区虽没有进程执行,但有些进程需要进入临界区,不能无限期地延长下一个要进入临界区进程的等待时间.有限等待(BoundedWaiting)。在一个进程提出进入临界区的请求和该请求得到答复的时间内,其他进程进入临界区前的等待时间必须是有限的.假定每个进程都以非零的的速率执行.没有任何关于这n个进程相对执行速率的假定.同步机制应遵循的准则空闲则入:其他进程均不处于临界区;忙则等待:已有进程处于其临界区;有限等待:等待进入临界区的进程不能"死等";让权等待:不能进入临界区的进程,应释放CPU(如转换到阻塞状态)只有2个进程,P0

和P1Pi进程的通用结构

do{

进入区 criticalsection

退出区 remindersection }while(1);进程可以共享一些公共变量来同步它们的行为。解决问题的初始尝试共享变量:intturn;

初始turn=0turn==i

Pi

能进入临界区j=1-i进程Pi

do{

while(turn!=i);

临界区

turn=j;

剩余区 }while(1);满足互斥条件,但不满足有空让进算法1共享变量booleanflag[2];

初始flag[0]=flag[1]=false.flag[i]=true

Pi

准备进入临界区进程Pi

do{ flag[i]:=true;

while(flag[j]); criticalsection flag[i]=false;

remaindersection }while(1);满足互斥,但不满足有空让进需求。算法2合并算法1和2的共享变量.进程Pi

do{

flag[i]:=true;

turn=j;

while(flag[j]andturn=j); criticalsection

flag[i]=false; remaindersection }while(1);满足三个需求;解决了两个进程的临界区问题。算法3在进入临界区前,每个进程接收一个号码。具有最小号码的进程进入临界区。如果进程Pi和Pj接收到同样的号码,如果i<j

,则Pi先得到服务,否则Pj先得到服务。这种号码方案总是以递增序列产生号码;如:1,2,3,3,3,3,4,5...多进程临界区问题:面包店算法定义如下符合,按字典顺序(ticket#,processid#)若a<c

,(a,b)<(c,d),或若

a=c

和b<dmax(a0,…,an-1)是数字

k,从而k

ai,对

i=0,…,n–1共享数据:

booleanchoosing[n]; intnumber[n];这些数据结构分别被初始化为false和0

面包店算法do{

choosing[i]=true; number[i]=max(number[0],number[1],…,number[n–1])+1; choosing[i]=false;

for(j=0;j<n;j++){ while(choosing[j]); while((number[j]!=0)&&(number[j,j]<number[i,i])); } criticalsection

number[i]=0; remaindersection}while(1);面包店算法原子地检查和修改字的内容.

booleanTestAndSet(boolean&target){ booleanrv=target; tqrget=true; returnrv; }硬件同步共享数据:

booleanlock=false;

进程Pi

do{ while(TestAndSet(lock));

criticalsection lock=false;

remaindersection }

Test-and-Set指令实现互斥原子地交换两个变量:

voidSwap(boolean&a,boolean&b){ booleantemp=a; a=b; b=temp; }硬件同步共享数据(初始化为

false):

booleanlock; booleanwaiting[n];

进程Pi

do{ key=true; while(key==true) Swap(lock,key);

criticalsection lock=false;

remaindersection }Swap指令实现互斥信号量Semaphore一种不需要忙等待的同步工具.信号量S–整型变量仅能通过两个不可分割的[原子]操作访问

P(S):whileS0dono-op;

S--;

V(S):S++;P(S)和V(S)操作不可中断。整型信号量的问题:忙等去除忙等的信号量P(S){ S--; if(S<0){ addthisprocesstolist block }}V(S){ S++; if(S<=0){ removeaprocessPfromlist wakeup(P); }}思考:S值的含义是什么?作为互斥工具的信号量SemaphoreS;//初始化为1P(S);CriticalSection()//临界区V(S);信号量的使用:S必须置一次且只能置一次初值,初值不能为负数除了初始化,只能通过执行P、V操作来访问S信号量的用法死锁和饥饿死锁–两个或多个进程无限期地等待一个事件的发生,而该事件正是由其中的一个等待进程引起的.S和Q是两个初值为1的信号量

P0

P1

P(S); P(Q); P(Q); P(S);

V(S); V(Q); V(Q) V(S);饥饿–无限期地阻塞。进程可能永远无法从它等待的信号量队列中移去.两种类型信号量计数信号量–变化范围没有限制的整型值.二进制信号量–变化范围仅限于0和1的信号量;容易实现.可以将计数信号量S用作二进制信号量.同步信号量和互斥信号量数据结构: binary-semaphoreS1,S2; intC:初始化:

S1=1 S2=0 C=信号量

S的初值S作为二进制信号量的实现wait

操作

wait(S1); C--; if(C<0){ signal(S1); wait(S2); } signal(S1);

signal

操作

wait(S1); C++; if(C<=0) signal(S2); else signal(S1);信号量的实现经典同步问题有限缓冲区问题读者写者问题哲学家就餐问题生产者消费者问题CONSUMERPRODUCERempty初值为1,full初值为0单缓存生产者消费者问题解决方案P:Repeat生产一个产品;P(empty);送产品到缓冲区;V(full);UntilfalseC:RepeatP(full);从缓冲区中取产品;V(empty);消费产品;Untilfalse共享数据

semaphorefull,empty,mutex;

初始化:

full=0,empty=n,mutex=1多缓冲区问题

do{ …

produceaniteminnextp … wait(empty); wait(mutex); …

addnextptobuffer … signal(mutex); signal(full); }while(1);

生产者进程

do{ wait(full) wait(mutex); …

removeanitemfrombuffertonextc … signal(mutex); signal(empty); …

consumetheiteminnextc … }while(1);消费者进程读者写者问题读者写者问题有两组并发进程:读者和写者,共享一组数据区,要求:允许多个读者同时执行读操作;不允许读者、写者同时操作;不允许多个写者同时操作。读者优先如果读者来:1)无读者、写者,新读者可以读。2)有写者等,但有其它读者正在读,则新读者也可以读。3)有写者写,新读者等如果写者来:1)无读者,新写者可以写。2)有读者,新写者等待。3)有其它写者,新写者等待。读者写者问题解决方案读者:RepeatP(mutex);readcount:=readcount+1;ifreadcount=1thenP(w);V(mutex);读P(mutex);readcount:=readcount-1;ifreadcount=0thenV(w);V(mutex);Untilfalse写者:RepeatP(w);写V(w);Untilfalse思考第二类读者写者问题:写者优先条件:1)多个读者可以同时进行读2)写者必须互斥(只允许一个写者写,也不能读者写者同时进行)3)写者优先于读者(一旦有写者,则后续读者必须等待,唤醒时优先考虑写者)如何用PV操作实现?Shareddata SemaphorechopStick[]=newSemaphore[5];哲学家就餐问题哲学家就餐问题Philosopheri: while(true){ //getleftchopstick P(chopStick[i]); //getrightchopstick P(chopStick[(i+1)%5]); //eatforawhile

//returnleftchopstick V(chopStick[i]); //returnrightchopstick V(chopStick[(i+1)%5]); //thinkforawhile }哲学家就餐问题 为防止死锁发生可采取的措施:最多允许4个哲学家同时坐在桌子周围仅当一个哲学家左右两边的筷子都可用时,才允许他拿筷子。给所有哲学家编号,奇数号的哲学家必须首先拿左边的筷子,偶数号的哲学家则反之为了避免死锁,所以把哲学家分为三种状态,思考,饥饿,进食,并且一次拿到两只筷子,否则不拿。哲学家就餐问题state:array[0..4]of(Thinking,hungry,eating);ph:array[0..4]ofsemaphore;mutex:semaphore;i:0..4;哲学家就餐问题解决方案Proceduretest(i:=0…4);beginif(state[i]=hungry)And(state[(i-1)mod5]<>eating)And(state[(i+1)mod5]<>eating)

thenbeginstate[i]=eating

V(ph[i])endendProcedurephilosopher(i:0~4)BeginRepeatthinking;

state[i]:=hungry;

P(mutex);test(i);V(mutex);P(ph[i]);getleftchopstick;

getrightchopstick;

eating;

returnleftchopstick

returnrightchopstick;

UntileFalse哲学家就餐问题解决方案思考!!以上算法存在一个问题,请思考并提出解决方法。例子1.用P.V操作解决下图之同步问题:getcopyputfstg2.用P.V操作解决司机与售票员的问题司机进程:REPEAT启动车辆正常驾驶到站停车UNTIL…售票员进程:REPEAT关门售票开门UNTIL…例子P.V操作讨论

1)信号量的物理含义:S>0表示有S个资源可用;S=0表示无资源可用;S<0则|S|表示S等待队列中的进程个数。P(S):表示申请一个资源;V(S)表示释放一个资源。信号量的初值应该大于等于02)P.V操作必须成对出现,有一个P操作就一定有一个V操作。当为互斥操作时,它们同处于同一进程。当为同步操作时,则不在同一进程中出现。如果P(S1)和P(S2)两个操作在一起,那么P操作的顺序至关重要,一个同步P操作与一个互斥P操作在一起时同步P操作在互斥P操作前。而两个V操作无关紧要。信号量同步的缺点同步操作分散:信号量机制中,同步操作分散在各个进程中,使用不当就可能导致各进程死锁(如P、V操作的次序错误、重复或遗漏)易读性差:要了解对于一组共享变量及信号量的操作是否正确,必须通读整个系统或者并发程序;不利于修改和维护:各模块的独立性差,任一组变量或一段代码的修改都可能影响全局;正确性难以保证:操作系统或并发程序通常很大,很难保证这样一个复杂的系统没有逻辑错误;管程Monitors

管程是对提供线程安全机制的高度抽象.任一时刻在管程中只有一个线程是能运行的.monitormonitor-name{ //variabledeclarations publicentryp1(…){ … } publicentryp2(…){ … }}条件变量conditionx,y;调用x.wait的线程将一直等待到有另一个线程调用x.signal管程示意图带条件变量的管程monitorDP{ enum{THINKING;HUNGRY,EATING)state[5]; conditionself[5]; voidpickup(inti){ state[i]=HUNGRY; test(i); if(state[i]!=EATING)self[i].wait; }

voidputdown(inti){ state[i]=THINKING;//testleftandrightneighbors

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论