经典同步问题

生产者-消费者问题

问题描述

一组生产者进程和一组消费者进程共享一个初始为空、 大小为n的缓冲区,只有缓冲区没满时,生产者才能把消息放入缓冲区,否则必须等待:只有缓冲区不空时,消费者才能从中取出消息,否则必须等待。由于缓冲区是临界资源,它只允许一个生产者放入消息,或一个消费者从中取出消息。

分析

  1. 关系分析:可见生产者消费者之间存在互斥访问缓存区,且存在同步关系即生产者必须生产后消费者才能消费
  2. 整理思路:需要一个互斥信号量来互斥访问缓存区,同步关系存在缓存区满或空的情况,所以使用两个同步信号量来实现同步
  3. 信号量设置:mutex=1实现互斥,empty=N用来表示缓冲区为空,full=0表示缓冲区为空

伪代码

semaphore mutex = 1
semaphore empty = N
semaphore full = 0
producer(){
    while(1)
		生产产品
        P(empty)
        P(mutex)	
        放入缓存区
        V(mutex)
        V(full)   
}
Customer(){
    while(1)
        P(full)
        P(mutex)
        取出产品
        V(mutex)
        V(empty)
        消费
}

吃水果问题

问题描述

桌子上有一个盘子,每次只能向其中放入一个水果。爸爸专向盘子中放苹果,妈妈专向盘子中放橘子,儿子专等吃盘子中的橘子,女儿专等吃盘子中的苹果。只有盘子为空时,爸爸或妈妈才可向盘子中放一个水果:仅当盘子中有自己需要的水果时,儿子或女儿可以从盘子中取出。

分析

  1. 关系分析

    可见爸爸和妈妈存在互斥关系,而爸爸与女儿、妈妈与儿子存在同步关系,可以将其看成变相的双生产者-双消费者问题

  2. 整理思路

    使用plate实现互斥,而apple和orange实现同步

  3. 信号量设置

    plate=1,apple=0,orange=0

伪代码

semaphore plate = 1
semaphore apple = 0
semaphore orange = 0
dad(){
    while(1)
        生成苹果
        P(plate)
        放入苹果
        V(apple)
}
mom(){
    while(1)
        生成橘子
        P(plate)
        放入苹果
        V(orange)
}
son(){
    while(1)
        P(orange)
        取出橘子
        V(plate)}
daughter(){
    while(1)
        P(apple)
        取出苹果
        V(plate)}

读者-写者问题

问题描述

有读者和写者两组并发进程,共享一个文件,当两个或以上的读进程同时访问共享数据时不会产生副作用,但若某个写进程和其他进程(读进程或写进程)同时访问共享数据时则可能导致数据不一致的错误。因此要求:①允许多个读者可以同时对文件执行读操作;②只允许一个写者往文件中写信息:③任一写者在完成写操作之前不允许其他读者或写者工作:④写者执行写操作前,应让已有的读者和写者全部退出

分析

  1. 关系分析

    可见写者与写者之间、写者与读者之间存在互斥关系,如果此时为第一个读者我们则让写者休息,如果此时为最后一个读者我们则让写者开写,存在同步关系

  2. 整理思路

    互斥我们使用rw实现,保证互斥;使用count来记录当前有多少个读者,使用mutex来互斥修改count

  3. 信号量设置

    rw=1,mutex=1

伪代码1:读者优先

semaphore rw = 1
semaphore muetx = 1
int count = 0
writer(){
    while(1)
        P(rw)
        写
        V(rw)
}
reader(){
	while(1)
       	P(mutex)
        if (count == 0)
            P(rw)
        count++
        V(mutex)
        看书
        P(mutex)
        count--
        if (count == 0)
            V(rw)
        V(mutex)
}

可见伪代码1存在一定问题,如果系统中有无数的读者进程,则写者将存在饥饿

伪代码2:写者优先或读写公平

使用w信号量,如果此时写者要写,则让写者先写

semaphore rw = 1
semaphore muetx = 1
semaphore w = 1
int count = 0
writer(){
    while(1)
    	P(w)
        P(rw)
        写
        V(rw)
        V(w)
}
reader(){
    while(1)
        P(w)						# 无写进程时访问
        P(mutex)
        if (count == 0)
            P(rw)
        count++
        V(mutex)					# 恢复共享文件
        V(w)
        看书
        P(mutex)
        count--
        if (count == 0)
            V(rw)
        V(mutex)
}

哲学家进餐问题

问题描述

一张圆桌边上坐着 5名哲学家,每两名哲学家之间的桌上摆一根筷子,两根筷子中间是一碗米饭。哲学家们倾注毕生精力用于思考和进餐,哲学家在思考时,并不影响他人。只有当哲学家饥饿时,才试图拿起左、右两根筷子(一根一根地拿起)。若筷子已在他人手上,则需要等待。饥饿的哲学家只有同时拿到了两根筷子才可以开始进餐,进餐完毕后,放下筷子继续思考。

分析

  1. 关系分析

    可见哲学家对中间的筷子有互斥关系

  2. 整理思路

    让哲学家拿起左右两个筷子即可,有两种解决方案:一次拿起两个筷子或对每个哲学家设置规则,防止死锁

  3. 信号量设置

    chopsticks[5],即可

伪代码1:存在死锁

semaphore chopsticks[5] = [1, 1, 1, 1, 1]
Pi(){
    while(1)
        P(chopsticks[i])			# 拿左边的筷子
        P(chopsticks[(i+1)%5])		# 拿右边的筷子
        吃饭
        V(chopsticks[(i+1)%5])
        V(chopsticks[i])
}

可见存在死锁,即哲学家同时拿起左筷子;

解决方法:限制一次只能四个人拿筷子,或一次都拿完

伪代码2:一次只能最多四个人

semaphore chopsticks[5] = [1, 1, 1, 1, 1]
semaphore person = 4
Pi(){
    while(1)
        P(person)					# 判断我能不能拿
        P(chopsticks[i])			# 拿左边的筷子
        P(chopsticks[(i+1)%5])		# 拿右边的筷子
        吃饭
        V(chopsticks[(i+1)%5])
        V(chopsticks[i])
        V(person)
}

伪代码3:一次性拿完

semaphore chopsticks[5] = [1, 1, 1, 1, 1]
semaphore mutex = 1
Pi(){
    while(1)
        P(mutex)					# 判断我能不能拿
        P(chopsticks[i])			# 拿左边的筷子
        P(chopsticks[(i+1)%5])		# 拿右边的筷子
        V(mutex)
        吃饭
        P(mutex)
        V(chopsticks[(i+1)%5])
        V(chopsticks[i])
        V(mutex)
}

吸烟者问题

问题描述

假设一个系统有三个抽烟者进程和一个供应者进程。每个抽烟者不停地卷烟并抽掉它,但要卷起并抽掉一支烟,抽烟者需要有三种材料:烟草、纸和胶水。三个抽烟者中,第一个拥有烟草,第二个拥有纸,第三个拥有胶水。供应者进程无限地提供三种材料,供应者每次将两种材料放到桌子上,拥有剩下那种材料的抽烟者卷一根烟并抽掉它, 并给供应者一个信号告诉已完成,此时供应者就会将另外两种材料放到桌上,如此重复(让三个抽烟者轮流地抽烟)。

分析

  1. 关系分析

    供应者与三个抽烟者有同步关系,且三个抽烟者轮流抽烟(互斥),抽完烟让供应者继续生产

  2. 整理思路

    供应者为生产者,抽烟者为消费者

  3. 信号量设置

    通过offer1,offer2,offer3来表示供应者三种组合,finish用来互斥抽烟

伪代码

int num = 0
semaphore offer1=0, offer2=0, offer3=0, finish=0
provider(){
	while(1)
        num++
        num = num % 3
        if num == 0
            V(offer3)			# 烟草和纸
        if num == 1
            V(offer1)			# 胶水和纸
        if num == 2
            V(offer2)			# 烟草和胶水
        P(finish)
}
P1(){
    P(offer1)
    抽烟
    V(finish)
}
P2(){
	P(offer2)
    抽烟
    V(finish)
}
P3(){
	P(offer3)
    抽烟
    V(finish)
}

总结

我还是不会同步问题,寄
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值