使用Semaphore解决经典的IPC问题

1. Producer-consumer problem 生产者消费者问题

问题关键:

生产者与消费者共同使用的队列大小有限,生产者不能过快地生产导致队列溢出,消费者不能无限消费导致消费了NULL。

要求:

1. 如果队列满了,生产者必须等待;消费者每次消费完一个产品,都应该及时通知生产者。

2. 如果队列空了,消费者必须等待;生产者每次生产一个产品,都应该及时通知消费者。

用semaphore实现:

111327_QkIa_2242731.png

分析:

使用了3个semaphore,第一个mutex作为互斥锁,用于互斥作用防止race condition;第二个avail表示容器中空位的个数,起始值这里是100;第三个fill表示,容器内当前产品的个数。其中,第二第三个semaphore除了作为counter,还起到通知作用,协助整个实现的沟通。

生产者的代码中,(1) 首先调用 wait(&avail)表明需要一个空位,如果当前容器里空位不够,则生产者被block,直到消费者调用post(&avail)通知有新的空位;如果当前容器空位充足(大于0),则(2) 调用 wait(&mutex) 获取互斥锁,如果消费者已经进入关键区域,则生产者被block,直到消费者调用post(&mutex)通知互斥锁可用; 获取到互斥锁后,(3)生产者将产品放入容器。接着,(4)调用post(&mutex) 生产者释放互斥锁,(5)调用post(&fill) 生产者通知消费者有新的产品进入容器。

消费者的代码逻辑相似。

 

2. Dining philosopher 进餐的哲学家问题

N位哲学家围绕着圆桌就餐,餐桌上有N支筷子,摆在哲学家左右两侧,哲学家时而进入思考状态,时而拿起左右两侧的筷子吃点东西,吃完后又将筷子放回原位。哲学家只能拿到自己左右两侧的筷子,而且一定需要两支筷子才能进餐。

简单的实现:

每位哲学家就餐前先拿起自己左侧的筷子,然后拿起右侧的筷子,吃完后,再依次放下左右两侧的筷子。

问题:

死锁。 每位哲学家都只拿到了自己左侧的筷子,等待右侧的筷子。(由于桌子是圆的,最后一位哲学家右侧的筷子恰好是第一位哲学家左侧的筷子)

 

简单解决方案:

采用随机等待放弃方案,当一位哲学家拿到了左侧筷子,等待右侧筷子超过一定时间时,就放弃进餐,放下左侧筷子,进入思考状态。

问题:

仍然可能出现问题,参考https://my.oschina.net/Bruce370/blog/885670 的要求二。某些特定情况下,每位哲学家都同时拿起左侧筷子等待右侧筷子,最后都同时放弃进餐,导致所有哲学家都没有进餐,违反了 “Bounded Waiting 有限等待” 原则。

 

一种可行方案:

改变上述方案的思路,将重点放在哲学家而不是筷子上,即一位哲学家进餐不是检查左右侧的筷子是否可用,而是检查左右侧的哲学家是否正在进餐。最后,引入一位"服务员",帮助通知哲学家进餐时机。

115515_Rn09_2242731.png

state数组存放的是哲学家的状态,包含 HUNGRY, EATING, THINKING三种状态。

mutex是互斥锁。

p数组是N个semaphore代表哲学家。

captain方法,检查特定的哲学家当前状态是否是HUNGRY,且左右两侧的哲学家都不在进餐,如果都符合就通知这位哲学家进餐。

 

评价:该方案不是最好的方案,可以google到更多有趣的解法。

 

小结:

由上述两个例子可以看出,semaphore不仅可以作为互斥锁,更重要的是,它能起到通知作用,从而解决系统的同步问题。

 

 

 

转载于:https://my.oschina.net/Bruce370/blog/885882

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值