目录
一、进程同步(重难)
- 理解临界资源和临界区的概念
- 熟练掌握利用信号量机制解决进程同步问题
1.进程同步基本概念
(1)进程同步任务
对多个相关进程在执行次序上进行协调,使并发执行的诸进程之间能有效地共享资源和相互合作,从而使程序的执行具有可再现性
(2)进程制约关系
- 间接相互制约关系——源于资源共享(进程AB想要访问打印机,AB之间没有直接关系,但因为打印机资源的共享而产生一种制约关系)
- 直接相互制约关系——源于进程合作(进程A往缓冲区放数据,进程B往缓冲区读数据,A放了数据后B才能读取,B读了之后A才能放,还有流水工作为生成一个商品每道工序按照次序协调执行)
(3)临界资源
临界资源:把一段时间内只允许一个进程访问的资源称为临界资源或独占资源
生产者—消费问题:
生产者进程和消费者进程都以异步方式运行,但它们之间必须保持同步
异步:生产者不用管消费,生产就行;消费者不用管生产,消费就行
同步:生产满了生产者要等消费者消费;消费完了消费者要等生产者生产,有这么一个次序
这个buffer是线性的,消费完了之后指针还要移动到开头,所以后面使用循环Buffer
生产者进程和消费者进程共享的变量:
缓冲池组织为循环缓冲,输入指针+1表示为in:=(in+1)mod n,输出指针+1表示为out:=(out+1) mod n,当(in+1) mod n=out时表示缓冲池满,in=out表示缓冲池空
程序如下——
先生产再消费这样顺序执行是不会出现问题的,但是当生产者进程和消费者进程并发操作时会出现问题,因为counter是公共资源
互斥访问:生产者存数据时,消费者不能使用缓冲区;消费者读数据时,生产者不能存数据
(4)临界区
临界区:每个进程中访问临界资源的那段代码称为临界区
为了保证进程能够互斥访问临界资源、执行操作,把访问临界区的程序设计为:
- 对欲访问的临界资源进行检查(如检查教室是否空闲)
- 若此刻未被访问,设正在访问的标志(申请资源,如向教务处申请教室)——进入区
- 访问临界资源(使用资源) ——临界区
- 将正在访问的标志恢复为未被访问的标志(释放资源) ——退出区
- 其余部分(善后操作:保存结果、状态等,如打扫一下教室) ——剩余区
进程互斥:两进程不能同时进入同一临界区
(5)同步机制应遵循规则
- 空闲让进(无人进)
- 忙则等待(有人使用则等待)
- 有限等待(等但不能等太久)
- 让权等待(如要使用打印机,但是打印机忙碌,应该主动放弃cpu,让cpu调度其他进程)
2.信号量机制
发展:整型信号量——>记录型信号量——>AND型信号量——>信号量集
- 信号量是OS提供的管理公有资源的有效手段
- 信号量代表可用资源实体的数量
比如有两台打印机,那么信号量为2;使用信号量对打印机这类公用临界资源进行管理,从而保证它们互斥访问
(1)整型信号量
定义:把整型信号量定义为一个用于表示资源数目的整型量S,除初始化外,仅能通过两个原子操作wait(S),signal(S)来访问
除了初始化,只有P、V操作能够改变S的值
P、V操作是原子操作,不可中断
P操作中的While S<=0 do no-op;未遵循“让权等待”原则,没有主动释放cpu,会导致忙等
(2)记录型信号量(重)
记录型信号量可以解决忙等的情况,引入整型变量value(代表资源数目)、进程链表L(链接所有等待进程)
记录型数据结构:
Wait操作:
- 申请资源,减量操作,S.value:=S.value-1
- 当S.value<0时,表示资源分配完,进行自我阻塞
Signal操作:
- 释放资源,增量操作,S.value:=S.value+1
- 当S.value≤0,唤醒S.L链表中的等待进程
value>0:可用资源的数量
value<0:由于申请资源而阻塞的进程数量
举例:进程A、B申请打印机资源,打印机有1台,所以S.value=1
假设A先访问打印机,则A进入到进入区执行P操作,S.value=1-1=0,S.value不小于0,进程A进入临界区执行打印操作。
打印过程中,进程B也要使用打印机,则B进入进入区执行P操作,S.value=0-1=-1,S.value<0,进程B被阻塞挂起到L上,直到进程A用完打印机,进入退出区执行V操作,S.value=-1+1=0,S.value<=0,唤醒进程B,把打印机给B用,B用完后释放资源执行V操作,S.value=0+1=1
【题目】
C
(3)AND型信号量
以上都是申请一类资源,如果还想申请其他资源怎么办?
两个进程A和B,共享数据D和E,为其分别设置互斥信号量Dmutex和Emutex,初值均为1
进程A、B并发执行时,可能发生死锁情况
A占用了D变量,需要E变量;B占用了E变量,需要D变量
共享的资源越多,死锁的可能越大
于是引入AND型信号量,AND同步机制的基本思想:将进程在整个运行过程中需要的所有资源,一次性全部分配给进程,待进程使用完后再一起释放。只要尚有一个资源未能分配给进程,其他所有可能为之分配的资源,也不分配给它,即对临界资源的分配采取原子操作。
以下是P操作和V操作的程序实现
(4)信号量集
前三种信号量都是-1,当一次需要 N 个单位时,便要进行 N 次 Wait(S) 操作,这显然是低效的。引入信号量集以每次能够获得或释放多个资源
每次分配前必须检查资源数量是否大于其下界值,信号量集是对AND信号量机制的扩充——S为信号量;t为下限值;d为需求值
如有10间教室(S=10),班长计算一下觉得3间教室足够了(t=3),但是以防万一最好申请5间教室(d=5)
信号量集可以一次性处理多种多个资源
一般信号量集的几种特殊情况——
- Swait(S,d,d),只有一个信号量S,允许每次申请d个资源,若现有资源数少于d,不予分配
- Swait(S,1,1),退化为一般的记录型信号量(S>1时,资源数量大于1)或互斥信号量(S=1,临界资源)
- Swait(S,1,0),当S>=1时,允许多个进程进入某特定区,当S变为0后,阻止任何进程进入特定区,相当于可控开关
3.信号量的应用
(1)利用信号量实现进程互斥
为使多个进程互斥地访问某临界资源,须为该资源设置一互斥信号量mutex,并设其初始值为1(互斥信号量表示S=1,某资源数目只有1个),然后将各进程访问资源的临界区CS置于wait(mutex)和signal(mutex)之间
进程1先访问资源(以打印机资源为例),执行P操作,mutex=1-1=0,mutex不小于0,进程1进入临界区使用资源,此时如果进程2也要使用打印机资源,执行P操作,mutex=0-1=-1,mutex小于0,进程2阻塞挂到L上,进程1执行完打印操作后,执行V操作,mutex=-1+1=0,mutex<=0,进程2被唤醒,执行打印操作
wait(mutex)和 signal(mutex)必须成对出现
若有三个或多个进程,则在parbegin和parend之间平行地写三个或多个进程
(2)利用信号量实现前驱关系
设有两个并发执行的进程P1和P2,P1中有语句S1,P2中有语句S2,希望在S1执行后再执行S2。
实现方案:使进程P1和P2共享一个公用信号量S,并赋予其初值为0
如下所示
正确次序执行:先执行进程P1,则先执行S1语句,然后执行V操作,S=0+1=1;然后执行进程P2,则先执行P操作,S=1-1=0,S不小于0,然后执行S2语句。
错误次序执行:先执行进程P2,则先执行P操作,S=0-1=-1,S<0,进程2阻塞,被挂在L上;然后执行进程P1,则先执行S1语句,然后执行V操作,S=-1+1=0,S<=0,唤醒进程2...
所以并发执行时,不管先执行了P1还是先执行了P2,最后都能按照前驱关系正确执行
规律:有几个箭头就有几个前驱关系,就设置几个信号变量,初值为0;语句之前有几个前驱就写几个P操作,有几个后继就写几个V操作,在P、V操作之间执行语句
题目:
使用信号量实现以上前驱关系
(3)利用记录型信号量实现同步
P1,P2两进程因合作完成一项任务而共用一个变量x。进程P2将处理结果送入x,进程P1将x的结果打印
实现方案:定义两个信号量empty=1,full=0【empty和full为资源信号量】
一个变量x可以看作一个位置的缓冲区,初始时缓冲区为空,所以empty=1,full=0
如果缓冲区有n个位置,那么empty=n,full=0,此时n表示缓冲区中可以用的位置
正确次序执行:先执行P2进程,则执行P操作,empty=1-1=0,empty不小于0,接着执行赋值操作,然后执行V操作,full=0+1=1;然后执行P1进程,则执行P操作,full=1-1=0,full不小于0,接着执行打印操作,然后执行V操作,empty=0+1=1
其他次序执行:先执行P2进程,则执行P操作,empty=1-1=0,empty不小于0,接着执行赋值操作,如果此时执行P1操作,则执行P操作,full=0-1=-1,full<0,阻塞进程1挂在L上,然后进程2中执行V操作,full=-1+1=0,full<=0,唤醒P1操作
其他次序执行:先执行P1进程,则执行P操作,full=0-1=-1,empy小于0,阻塞进程1挂在L上,然后执行进程2,则执行P操作,empty=1-1=0,empty不小于0,执行赋值操作,然后执行V操作,full=-1+1=0,full<=0,唤醒P1操作
特点:同一进程中wait和signal对应不同的信号量
【题目1】在操作系统中引入“进程”概念的主要目的是()
A.改善用户编程环境 B.提高程序的运行速度
C.描述程序动态执行过程的性质 D.使程序与计算过程一一对应
【题目2】有9个生产者,6个消费者,共享容量为8的缓冲区,在这个生产者-消费者问题中,互斥使用缓冲区的信号量mutex的初值应该为()
A.1 B.6 C.8 D.9
C、A
二、经典的进程同步问题(重)
1.生产者-消费者问题
考虑两个问题——有几个进程?存在哪些工作方式?
①有两个进程
②既存在互斥关系又存在同步关系
- 任何时刻只能有一个进程可对共享缓冲区进行操作,共享缓冲区的生产者与生产者之间、生产者与消费者之间以及消费者与消费者之间存在互斥关系
- 缓冲区不满,生产者才能写入;缓冲区不空,消费者才能读出,可知生产者与消费者之间存在同步关系
(1)记录型信号量
利用记录型信号量解决生产者—消费者问题。
对于互斥关系,定义一个互斥信号量mutex=1;对于同步关系,定义两个资源信号量empty=n,full=0
程序如下——
执行生产者进程时首先要判断是否还有空位,然后判断是否有进程正在使用共享的缓冲区,都没问题则进入临界区执行存放操作,退出时执行两个V操作
执行消费进程时首先要判断是否还有非空位,然后判断是否有进程正在使用共享的缓冲区,都没问题则进入临界区执行读取操作,退出时执行两个V操作
注意——
- 每个程序中用于实现互斥的wait(mutex)和signal(mutex)必须成对地出现
- 对资源信号量empty和full的wait和signal操作,同样需要成对地出现,但出于不同的程序中
- 在每个程序中多个wait操作顺序不能颠倒。应先执行对资源信号量的wait操作,再执行对互斥信号量的wait操作,否则可能引起进程死锁,释放时顺序可以颠倒【假设颠倒,先执行消费者进程中的wait(mutex),mutex=1-1=0,然后执行wait(full),full=0-1=-1,消费者进程阻塞挂到L上;然后执行生产者进程中的wait(mutex),mutex=0-1=-1,mutex小于0,阻塞,这样就产生了死锁】
先做同步,后做互斥
(2)AND信号量
利用AND信号量解决生产者—消费者问题。
2.哲学家进餐问题
五个哲学家共用一张圆桌,分别坐在周围的五张椅子上,在桌子上有5只碗和5支筷子,他们的生活方式是交替地思考和进餐。平时,一个哲学家进行思考,饥饿时便试图取用其左右最靠近他的筷子,只有在他拿到两只筷子时才能进餐。进餐毕,放下筷子继续思考
可见:相邻两位不能同时进餐;最多只能有两人同时进餐(两双半筷子)
如果5个人同时饿了会饿死,如何解决这个问题?
5个哲学家即5个进程,放在桌子上的筷子是临界资源,在一段时间内只允许一个哲学家使用。为实现对筷子的互斥使用,用一个信号量表示一只筷子,五个信号量构成信号量数组。
0号哲学家:C0和C1; 1号哲学家:C1和C2; 2号哲学家:C2和C3; 3号哲学家:C3和C4; 4号哲学家:C4和C0;
所以第i位哲学家的活动可描述为:
该算法虽能保证相邻两位不会同时进餐,但有可能引起死锁。
假如五位哲学家同时饥饿而各自拿起左边的筷子时,就会使五个信号量chopstick均为0,当他们再试图去拿右边的筷子时,都将因无筷子可拿而无限等待
解决办法——
- 至多只允许有4位哲学家同时去拿左边的筷子,最终能保证至少有一位哲学家能够进餐,并在用毕后释放出他用过的两只筷子,从而使更多的哲学家能够进餐
- 仅当哲学家的左右两只筷子均可用时,才允许他拿起筷子进餐
- 规定奇数号哲学家先拿他左边的筷子,然后再去拿右边的筷子;偶数号哲学家则相反【如2号哲学家拿C3筷子,3号哲学家拿C3筷子,4号哲学家拿C5筷子】
(1)方法一
(2)方法二
利用AND信号量机制解决哲学家进餐问题,每个哲学家先获得两个临界资源(筷子)后方能进餐
(3)方法二
3.读者-写者问题
对共享资源的读写操作,任一时刻“写者”最多只允许一个,而“读者”则允许多个,要求: “ 读-写” 互斥;“ 写-写” 互斥;“ 读-读” 允许
“读者—写者问题”是保证一个Writer进程必须与其他进程互斥地访问共享对象的同步问题(有读者读取要等读者读完才能写或其他写者写完才能写)
(1)记录型信号量
解:需要设置互斥信号量Wmutex =1,以读写进程和写写进程能够互斥访问共享资源
读—读允许——引入变量Rcount 表示“正在读”的进程数,初值是 0 ,第一个读进程需要检查Wmutex是否可以读,后面的进程不需要检查,直接读(有读进程访问了肯定不会有写进程)当 reader 进程执行了 Rcount 减 1 操作后,其值为 0 时,才须执行 V(Wmutex) 操作;因为Rcount是公共变量,所以需要一个互斥信号量Rmutex 来互斥访问,否则就会像生产者-消费者问题中的count出现问题
这样子能实现读者—写者问题,但读优先,对写者不公平【如果有很多读进程,读进程先访问了资源,那么写进程要一直等到所有读进程全部读完,才能申请上Wmutex】
(2)信号量集
为了让读写机会平等,使用信号量集机制来解决读者—写者问题
增加一个限制:最多只允许RN个读者同时读(之前是无限地读,有多少读进程就读多少)。为此引入信号量L,赋予初值RN,通过执行Swait(L,1,1)操作来控制读者的数目
每当有一个读者进入时,就要先执行Swait(L,1,1)操作,使L的值减1。当有RN个读者进入读后,L便减位0,第RN+1个读者要进入读时,必然会因Swait(L,1,1)操作失败而阻塞
②语句起着开关的作用。只要无writer进程进入写,Wmutex=1,reader进程就都可以进入读。但只要一旦有writer进程进入写时,Wmutex=0,则任何reader进程都无法进入读
③语句表示仅当既无writer进程在写(Wmutex=1),又无reader进程在读(L=RN),writer进程才能进入临界区写
【问题1】有三个进程 PA 、 PB 和 PC 协作解决文件打印问题。PA 将文件记录从磁盘读入内存的缓冲区 1 ,每执行一次读一个记录;PB 将缓冲区 1 的内容复制到缓冲区 2 中,每执行一次复制一个记录;PC 将缓冲区 2 的内容打印出来,每执行一次打印一个记录。缓冲区的大小与记录大小一样。请用信号量来保证文件的正确打印。
解:①存在三个运行主体,缓冲区1和缓冲区2是临界资源。
PA与PB对缓冲区1的访问是互斥操作;PB与PC对缓冲区2的访问是互斥操作【mutex1和mutex2分别是缓冲区1和缓冲区2的互斥信号量,初值均为1】
对资源的读取是同步操作【定义4个信号量empty1=1,full1=0;empty2=1,full2=0】
【问题2】桌上有个能盛得下五个水果的空盘子。爸爸不停地向盘中放苹果或桔子,儿子不停地从
盘中取出桔子吃,女儿不停地从盘中取出苹果吃。规定三人不能同时从盘子中取放水果。试用信号量实现爸爸、儿子和女儿这三个循环进程之间的同步
解:这是生产者-消费者的变形。生产者是父亲,能生产出两种产品;消费者是儿子和女儿(一个消费桔子,一个消费苹果)。
三人不能同时从盘子中取放水果,互斥操作mutex=1
对资源的读取是同步操作【empty=5,apple=0,orange=0】full分成了apple和orange
【问题3】请用信号量机制解决以下的“过独木桥”问题:同一方向的行人可连续过桥,当某一方向有人过桥时,另一方向的行人必须等待;当某一方向无人过桥时,另一方向的行人可以过桥。
解:对于东西两侧的车辆而言,桥是一个互斥资源,而对东西两侧各自而言,每辆车上桥是同步关系,东西两侧的车辆在抢到这互斥资源后只有最后一辆车通过了独木桥才释放,所以需要记录上桥车子的数量
这个问题和读者优先的读写问题很相似【同一方向的行人可以同时过桥,这相当于读者可以同时读。因此,可将两个方向的行人看作两类不同的读者,同类读者 ( 行人 ) 可以同时读 ( 过桥 ) ,但不同类读者 ( 行人 ) 之间必须互斥地读 ( 过桥 ) 】。
【问题4】设有两个生产者进程 A 、 B 和一个销售者进程 C ,他们共享一个无限大的仓库,生产者每次循环生产一个产品,然后入库供销售者销售;销售者每次循环从仓库中取出一个产品进行销售。不允许同时入库,也不允许边入库边出库;而且要求生产 A 产品和 B 产品的件数满足以下关系: -n<=A 的件数 -B 的件数 <=m ,其中 n 、 m 是正整数,但对仓库中 A 产品和 B 产品的件数无上述要求。请用信号量机制写出 A 、 B 、 C 三个进程的工作流程
解:题中存在着以下的同步和互斥关系:
①生产者A、B和消费者C之间,不能同时将产品入库和出库,仓库是一个临界资源
②两个生产者之间必须进行同步,当生产A、B产品的件数只差>=m时,生产者A必须等待;当生产A、B产品的件数之差<=-n,生产者B必须等待。可想象成有两种令牌,分别跟允许A和B生产的产品数量相关,A和B必须取得对应的令牌后才能生产产品,故这两类令牌也就是两种临界资源
③生产者和销售者这件也必须取得同步,只有当生产者上产出产品并入库后,销售者才能进行销售【无限大仓库无需考虑full】
信号量定义如下:
①为了互斥地入库和出库,为仓库设置互斥信息量,mutex=1 ;
②为了使生产的产品件数满足: -n<=A 的件数 -B 的件数 <=m ,需设置两个信号量,其中 SAB 表示当前允许A 生产的产品数量,其初值为, SAB=m ; SBA 表示当前允许 B 生产的产品数量,其初值为 , SBA =n ;
③设置一个初值为 0 的资源信号量 S ,对应于仓库中的产品数量, S=0 。
【问题5】某寺庙有小和尚,老和尚若干,有一水缸,由小和尚提水入缸供老和尚饮用。水缸可容 10 桶水,水取自同一井中。水井径窄,每次只能容一个桶取水。水桶总数为 3个,每次入缸取仅为 1 桶水,且不可同时进行。试给出有关从缸取水、入水的算法描述。
解:①小和尚和老和尚的同步关系:小和尚提水放入水缸,老和尚从水缸取水喝,水缸满了,小和尚不能倒水,水缸空了,老和尚不能喝水,是一个典型的生产者消费者模式【为了实现同步,设置资源信号量empty=10,full=0】
②互斥——
水桶只有3个,打水和喝水都需要用水桶,所以小和尚和老和尚之间均存在这个制约关系;
其次,水井比较窄,每次只能一个水桶取水,所以小和尚打水也需要互斥;
最后,水缸取水每次只能1桶水,不可以同时进行,所以小和尚倒水和老和尚取
水也需要互斥。
定义互斥信号量 bucket,初值为3,代表水桶初始数量;
定义互斥信号量well,初值为1,代表取水需要互斥(水井互斥):
定义互斥信号量 water,初值为1,代表水缸的入水和取水需要互斥(水缸互斥);