进程的同步与通信.docx

上传人:b****6 文档编号:8548339 上传时间:2023-01-31 格式:DOCX 页数:43 大小:62.71KB
下载 相关 举报
进程的同步与通信.docx_第1页
第1页 / 共43页
进程的同步与通信.docx_第2页
第2页 / 共43页
进程的同步与通信.docx_第3页
第3页 / 共43页
进程的同步与通信.docx_第4页
第4页 / 共43页
进程的同步与通信.docx_第5页
第5页 / 共43页
点击查看更多>>
下载资源
资源描述

进程的同步与通信.docx

《进程的同步与通信.docx》由会员分享,可在线阅读,更多相关《进程的同步与通信.docx(43页珍藏版)》请在冰豆网上搜索。

进程的同步与通信.docx

进程的同步与通信

第3章进程的同步与通信

3.2例题解析

例3.2.1多道程序系统程序的执行失去了封闭性和再现性,因此多道程序的执行不需要这些特性,这种说法是否正确?

解这种说法不正确。

可以想象,如果一个程序在多道程序系统中,在相同的输入的情况下,多次执行所得结果是不同的,有谁还敢使用这个程序?

因此,多道程序的执行也需要封闭性和再现性,只不过单道程序系统的封闭性和再现性是先天固有的,多道程序系统的程序执行要想获得封闭性和再现性,需通过程序员的精心设计才能得到。

所使用的方法就是同步和互斥的方法。

P例3.2.2多个进程对信号量S进行了5次P操作,2次V操作后,现在信号量的值是-3,与信号量S相关的处于阻塞状态的进程有几个?

信号量的初值是多少?

(1)因为S的当前值是-3,因此因为S处于阻塞状态的进程有3个;

(2)因为每进行一次P(S)操作,S的值都减1,每执行1次V操作S的值加1,故信号量的初值为-3+5-2=0;

例3.2.3如下锁的实现方法存在什么缺点?

如何改进?

LOCK(X)UNLOCK(X)

{{

dowhileX=1;X=0;

X=1

}}

解存在的缺点是:

当锁是关闭时,采用的是循环等待的方法,这样的等待还是要占用处理机的时间,应该采用阻塞等待的方法。

改进的锁实现如下:

LOCK(X)UNLOCK(X)

{{

ifX.value=1ifnotempty(X.L)

{insert(*,X.L);{P=remove(X.L);

Block(*)Wakeup(P)

}}

elseX.Value=1elseX.Value=0

}}

这里X.value是锁的值,X.L是存放由于锁X而阻塞的进程的队列。

insert(*,X.L)将当前进程的进程号插入到X.L,remove(X.L)是从X.L中移出一个进程号。

例3.2.4使用多个进程计算Y=F1(X)+F2(X).

(1)确定并发和顺序操作

在这个问题中,F1(X)和F2(X)的计算是可以并行处理的,因此F1(X)和F2(X)可以分别出现在两个进程中。

(2)确定互斥或同步的规则

在F1(X)+F2(X)中,必须在F1(X)和F2(X)计算完毕,才能进行加法运算,因此本问题是同步问题。

(3)同步的操作流程

〈进程main〉

创立进程p1来计算F1(X);

创立进程p2来计算F2(X);

F1(X)计算是否完成?

没有,等待;

F2(X)计算是否完成?

没有,等待;②

进行加法运算。

〈进程p1〉

y1=F1(X);

设置F1(X)计算完成标志;③

〈进程p2〉

y1=F2(X);

设置F2(X)计算完成标志。

(4)确定信号量的个数和含义

根据同步规则以及操作流程确定信号量的个数是2个,S1和S2:

S1含义是F1(X)计算是否完成;

S2含义是F2(X)计算是否完成。

(5)确定信号量的初值

S1=0;

S2=0。

(6)确定P、V操作的位置

上面①处是一个P操作,P(S1);

上面②处是一个P操作,P(S2);

上面③处是一个V操作,V(S1);

上面④处是一个V操作,V(S2)。

解法1

Main()

Publicy,y1,y2,.P1,P2

SemaphoreS1,S2

{

S1=0;

S2=0;

P1=Creat(N-F1,F1,x,……);

P2=Creat(N-F2,F2,x,……);

P(S1);

P(S2);

y=y1+y2;

}

ProcedureF1(x)

{

y1=计算1;

V(S1);

}

ProcedureF2(x)

{

y2=计算2;

V(S2)

}

解法2

Main()

Publicy,y1,y2,.P1,x

SemaphoreS1

{input(x);

S1=0;

P1=Creat(N-F1,F1,x,……);

Y2=F2(x);

P(S1);

y=y1+y2;

}

ProcedureF1(x)

{

y1=计算1;

V(S1)

}

采用2个进程和1个信号量来实现Y=F1(X)+F2(X)的时候,采用的方法是父进程创立子进程,F1(X)在子进程中计算,F2(X)在父进程中计算,因此F1(X)和F2(X)计算仍然是并发进行的。

S1信号量的含义为F1(X)是否完成。

改进的方法比原来的方法节约一个进程和一个信号量,但并发操作的程度并没有降低。

例3.2.5生产者—消费者问题演变。

情况1一个buffer,一个生产者,一个消费者,生产者只生产一个东西,消费者只进行一次消费,即:

生产者只进行一次putdata操作,消费者只进行一次getdata操作。

解这是一个同步问题,生产者和消费者分别是2个并发的进程。

(1)操作规则

如果buffer为空,则消费者只能等待。

(2)操作流程

<生产者>

{

putdata;

设置Buffer有数据标志V(S)

}

<消费者>

{

判断buffer是否有产品,没有则等待;

getdata;

}

(3)信号量

设置1个信号量full,full表示buffer是否有数据,初值为0。

(4)P、V操作实现

varfull:

semaphore:

=0;

buffer:

array[1]ofitem;

begin

parbegin

producer:

begin

putdata;

V(full);

end

consumer:

begin

P(full);

getdata;

end

parend

end

情况2一个buffer,一个生产者,一个消费者,生产者不断地进行putdata操作,消费者不断地进行getdata操作,即:

生产者不断地生产,消费者不断地消费

(1)操作规则

只有buffer为空时才能进行putdata操作;只有buffer有数据时才能进行putdata操作。

(2)操作流程

<生产者>

{

repeat

判断buffer是否为空,不空则等待;

putdata;

设置buffer有数据的标志;

untilfalse

}

<消费者>

{

repeat

判断buffer是否有数据,没有数据则等待;

getdata;

设置buffer为空标志;

untilfalse

}

(3)信号量

设置2个信号量full和empty。

full表示buffer是否有数据。

因为进程在初始状态时,buffer中没有数据,故初值为0,变化范围-1~1。

empty表示buffer是否为空。

因为进程在初始状态时,buffer为空,故初值为0初值为1,变化范围-1~1。

(4)P、V操作实现

varfull:

semaphore:

=0;

emptyl:

semaphore:

=1;

buffer:

array[1]ofitem;

begin

parbegin

producer:

begin

repeat

P(empty);

putdata;

V(full);

untilfalse

end

consumer:

begin

repeatP(full);

getdata;

V(empty);

untilfalse.

end

parend

end

情况3一个buffer,多个生产者,多个消费者,多个生产者和消费者都在不断地存取buffer,即生产者不断地进行putdata操作,消费者不断地进行getdata操作。

(1)操作规则

只有buffer为空时才能进行putdata操作;只有buffer有数据时才能进行putdata操作。

这时buffer变成了临界资源,不允许多个进程同时操作buffer,即不允许多个消费者同时进行gedata,不允许多个生产者同时进行putdata操作。

(2)操作流程

<生产者>

{

repeat

判断buffer是否为空,不则等待;

是否可操作buffer;

putdata;

设置buffer可操作标志;

设置buffer有数据的标志;

untilfalse

}

<消费者>

{

repeat

判断buffer是否有数据,没有则等待;

是否可操作buffer;

getdata;

设置buffer可操作标志;

设置buffer为空标志;

untilfalse

}

(3)信号量

设置3个信号量full、empty和B-M。

full表示buffer是否有数据,初值为0;

empty表示buffer是否为空,初值为1;

B-M表示buffer是否可操作,初值为1。

由于buffer只有一个,full和empty可以保证对buffer的正确操作,故B-M是多余的,可以省略。

(4)P、V操作实现

<生产者><消费者>

{{

repeatrepeat

P(empty);P(full);

P(B-M);  P(B-M);

putdata;getdata;

V(B-M);  V(B-M);

V(full);V(empty);

untilfalse.untilfalse

}}

情况4多个生产者,多个消费者,N个buffer,多次循环存取buffer,即,即多个生产者不断地进行putdata操作,多个消费者不断地进行getdata操作。

(1)操作规则

只有buffer有空间才能进行putdata操作;

只有buffer有数据才能进行putdata操作;

这时buffer变成了临界资源,不允许多个消费者和生产者同时对同一个buffer进行gedata和putdata操作。

(2)操作流程

<生产者>

{

repeat

判断buffer是否有空间,没有则等待;

是否可操作buffer;

putdata;

设置buffer可操作标志;

设置buffer有数据的标志;

untilfalse

}

<消费者>

{

repeat

判断buffer是否有数据,没有则等待;

是否可操作buffer;

getdata;

设置buffer可操作标志;

设置buffer有空间标志;

untilfalse

}

(3)信号量

full表示buffer是否有数据,初值为0;

empty表示buffer是否为空,初值为N;

B-M表示buffer是否可操作,初值为1。

(4)P、V操作实现

<生产者><消费者>

{{

repeatrepeat

P(empty);P(full);

P(B-M);  P(B-M);

putdata;getdata;

 V(B-M);  V(B-M);

V(full);V(empty);

untilfalseuntilfalse

}}

(5)改进的P、V操作实现

在上述的实现中,putdata和getdata操作都在临界区中,因此多个进程对多个buffer的操作是不能并发进行的,进程间并行操作的程度很低。

实际上只要保证多个进程同时操作不同buffer就可以实现对整个buffer的并行操作。

因此,只要保证为不同的进程分配不同buffer,putdata和getdata操作是可以同时进行。

这样互斥不是发生在对buffer的存取操作上,而是发生在对buffer的分配上,这个时间与存取buffer的时间相比是较短的,因此减少了进程处于临界区的时间。

这里引入2个函数:

 getE_buffer(),返回值是空的buffer号;

 getD_buffer(),返回值是有数据的buffer号。

getE_buffer()和getD_buffer()通过将buffer转换成循环队列的方法来实现对buffer的分配。

buffer设有Pbuff,Pdata两个指针,分别指向空闲buffer和有数据buffer 的头,每进行一次getE_buffer()和getD_buffer(),Pbuff和Pdata两个指针分别向后移动一个位置。

GetE_buffer()

{c=Pbuff

Pbuff=(Pbuff+1)MODN;

Return(c)

}

getD_data()

{c=Pdata;

Pdata=(pdata+1)MODN;

Return(c)

}

改进的程序描述如下:

varmutex.empty,full:

semaphore:

=1,n,0;

buffer:

array[0,…,n-1]ofitem;

Pbuff,Pdata:

integer:

=0,0;

begin

parbegin

producer:

begin

repeat

┇P(empty);

P(B_M);

in:

=getE_buffer();

V(B_M)

putdata(in);V(full);

untilfalse;

end

consumer:

begin

repeat

P(full);

P(B_M);out:

=getD_buffer();

V(B_M);

Getdata(out);

V(empty);

untilfalse

end

parend

end

P例3.2.6设公共汽车上,司机和售票员的活动分别为:

司机的活动为启动车辆,正常行车,到站停车;售票员的活动为关车门,售票,开车门。

试问:

(1)在汽车不断地到站、停车、行驶过程中,司机和售票员的活动是同步关系还是互斥关系?

(2)用信号量和P、V操作实现他们间的协调操作。

(1)确定并发和顺序操作

在这个问题中,司机与售票员间是并行操作的,司机和售票员本身的操作是顺序进行的。

因此司机是一个进程,售票员是一个进程,它们之间是同步关系。

(2)确定同步的规则

根据一般常识,司机和售票员在车上的操作规则如下:

1)售票员操作的规则是只有司机停车后,售票员才能开门让乘客上下车;

2)司机操作的规则是只有售票员关门后,司机才能启动开始行驶汽车。

可见,售票员关车门后,要向司机发开车信号,司机接到开车信号后才能启动车辆。

在汽车正常行驶过程中售票员售票,到站时司机停车,售票员在车停后开车门,让乘客上下车。

因此司机启动车辆的动作必须与售票员的动作取得同步;售票员开车门的动作也必须同司机停车取得同步。

(3)进程的操作流程

<售票员进程>

dowhileT

关车门;

设立车门已关标志;

售票;

是否停车?

没停则等待;

开车门;

上下乘客;

enddo

<司机进程>

dowhileT

是否关门?

没关则等待;

启动车辆;

正常行车;

到站停车;

设立车停标志;

enddo

(4)确定信号量的个数和含义

根据同步规则以及操作流程确定信号量的个数是2个,S1和S2。

S1的含义是否关门;

S2的含义是否停车。

(5)确定信号量的初值

S1=0;

S2=1。

(6)确定P、V操作的位置

司机操作中,是否关门?

没关则等待,这是一个P操作,P(S1);

司机操作中,设立停车标志,这是一个V操作,V(S2);

售票员操作中,是否停车?

没停则等待,这是一个P操作,P(S2);

售票员操作中,设立关门标志,这是一个V操作,V(S1)。

(7)P、V操作实现

intS1=0;

intS2=1;

main()

{

cobegin

driver();busman();

coend

}

driver()

{dowhileT

{P(S1);

启动车辆;

正常行车;

到站停车;

V(S2);

}

}

busserver()

{dowhileT

{关车门;

V(S1);

售票;

P(S2);

开车门;

上下乘客;

}

}

例3.2.7在OS中引入管程的目的是什么?

解在OS中引入管程的目的是为了更简便、更可靠地解决进程之间的同步、互斥问题。

在未引入管程之间,进程间的同步、互斥问题是由程序员处理的。

例如,在临界区的前后插入P、V操作。

但是,由程序员处理同步、互斥问题有可能引入种种人为的错误。

管程主要是管理对共享数据的操作和使用,即把对共享数据互斥使用的控制这一任务从程序员身上,交由编译程序去处理,这样既方便了编程,又不会产生人为的同步、互斥上的错误。

例3.2.8说明管程中条件变量的含义及作用。

解管程中的条件变量(类型为Condition)是供调用管程中外部过程的进程执行Wait和Signal操作将自己挂起和解挂的变量。

可通过与信号量的比较来认识条件变量:

(1)信号量要赋初值而条件变量不赋初值,它只是一个队首指针;

(2)在信号量上执行P操作的进程不一定会被阻塞,而在条件变量上执行Wait操作的进程肯定被挂起;

(3)在信号量上的V操作将导致信号量值加1,若增加后的值小于等于0,则要唤醒在信号量上等待的进程,但唤醒者不受什么影响;而在条件变量上的Signal操作却有两种处理方式:

P等待,直到Q离开管程,或等待另一条件;Q等待,直到P离开管程,或等待另一条件。

P、Q是两个进程。

P例3.2.9如果信号量S的初值是5,现在信号量的值是-5,那么系统中的相关进程至少执行了几个P(S)操作?

与信号量S相关的处于阻塞状态的进程有几个?

如果要使信号量S的值大于0,应该进行怎样的操作?

(1)因为每执行一次P操作S的值减1,5-(-5)=10,在这期间有可能有进程执行V操作,使S的值加1,所以至少执行了10次P(S);

(2)5个;

(3)6个V(S)或5个以上。

例3.2.10如下图所示,有多个PUT操作同时向BUFF1放数据,有一个MOVE操作不断地将BUFF1的数据移到Buff2,有多个GET操作不断地从Buff2中将数据取走。

BUFF1的容量为m,BUFF2的容量是n,PUT、MOVE、GET每次操作一个数据,在操作的过程中要保证数据不丢失。

试用P、V原语协调PUT、MOVE的操作,并说明每个信号量的含义和初值。

图4.2进程操作图

(1)确定并发的操作

本问题是把2个消费者和生产者问题综合在一起。

多个PUT操作与一个MOVE操作并发进行,多个GET操作与一个MOVE操作并发进行。

因此本题涉及三类进程:

PUT类进程,有多个;GET类进程,有多个;MOVE类进程,有1个。

(2)操作规则

1)只有buff1有空间才能进行PUT操作;

2)只有buff1有数据,buff2有空间才能进行MOVE操作;

3)只有buff2有数据才能进行GET操作;

4)不允许多个进程同时操作buff1;

5)不允许多个进程同时操作buff2。

(3)操作流程

{

repeat

判断buff1是否有空间,没有则等待;

是否可操作buff1;

PUT;

设置buff1可操作标志;

设置buff1有数据的标志;

untilfalse

}

{

repeat

判断buff1是否有数据,没有则等待;

判断buff2是否有空间,没有则等待;

是否可操作buff1;

是否可操作buff2;

MOVE;

设置buff1可操作标志;

设置buff2可操作标志;

设置buff1有空间标志;

设置buff2有数据标志;

untilfalse

}

{

repeat

判断buff2是否有数据,没有则等待;

是否可操作buff2;

GET;

设置buff1可操作标志;

设置buff1有空间标志;

untilfalse

}

(4)信号量

设置6个信号量full1、empty1、B-M1、full2、empty2、B-M2,它们的含义和初值如下:

1)full1表示buff1是否有数据,初值为0;

2)empty1表示buff1有空间,初值为m;

3)B-M1表示buff1是否可操作,初值为1;

4)Full2表示buff2是否有数据,初值为0;

5)Empty2表示buff2有空间,初值为n;

6)B-M2表示buff2是否可操作,初值为1;

(5)P、V操作实现

{

repeat

P(empty1);/*判断buff1是否有空间,没有则等待*/

P(B-M1);/*是否可操作buff1*/

PUT;

V(B-M1);/*设置buff1可操作标志*/

V(full1);/*设置buff1有数据的标志*/

untilfalse

}

{

repeat

P(full1);/*判断buff1是否有数据,没有则等待*/

P(empty2);/*判断buff2是否有空间,没有则等待*/

P(B-M1);/*是否可操作buff1*/

P(B-M2);/*是否可操作buff2*/

MOVE;

V(B-M1);/*设置buff1可操作标志*/

V(B-M2);/*设置buff2可操作标志*/

V(empty1);/*设置buff1有空间标志*/

V(full2);/*设置buff2有数据标志*/

untilfalse

}

{

repeat

P(empty2);/*判断buff2是否有空间,没有则等待*/

P(B-M2);/*是否可操作buff2*/

GET;

V(B-M2);/*设置buff2可操作标志*/

V(full2);/*设置buff2有数据的标志*/

untilfalse

}

P例3.2.11一售票厅只能容纳300人,当少于300人时,可以进入;否则,需在外等候。

若将每一个购票者作为一个进程,请用P、V操作编程,并写出信号量的初值。

解〈购票者进程〉

{┋

P(S);

进入售票厅;

购票;

退出售票厅;

V(S);

}

信号量的初值

S=300

P例3.2.12设A、B为两个并发进程,它们共享一个临界资源,其执行临界区的算法框图如下图所示。

试判断该算法是否有错?

请说明理由。

如果有错,请改正。

S1、S1的初值为0,CSA、CSB为临界区。

 

A进程B进程

 

图4.3进程操作图

分析咋一看,好像是A进程开始未执行P操作,便直接进入临界区,以为问题出在这里。

从图中可分析出A、B两进程的执行思路:

A进程对临界资源操作结束后,将其释放给B进程,而B进程对临界资源操作结束后,将释放给进程A。

系统初启时,S1、S2初值为0,则B执行P(S1)被阻塞,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 工学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1