使用Semaphore解决经典的IPC问题
2017-04-24 12:05
281 查看
1. Producer-consumer problem 生产者消费者问题
问题关键:
生产者与消费者共同使用的队列大小有限,生产者不能过快地生产导致队列溢出,消费者不能无限消费导致消费了NULL。
要求:
1. 如果队列满了,生产者必须等待;消费者每次消费完一个产品,都应该及时通知生产者。
2. 如果队列空了,消费者必须等待;生产者每次生产一个产品,都应该及时通知消费者。
用semaphore实现:
分析:
使用了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 有限等待” 原则。
一种可行方案:
改变上述方案的思路,将重点放在哲学家而不是筷子上,即一位哲学家进餐不是检查左右侧的筷子是否可用,而是检查左右侧的哲学家是否正在进餐。最后,引入一位"服务员",帮助通知哲学家进餐时机。
state数组存放的是哲学家的状态,包含 HUNGRY, EATING, THINKING三种状态。
mutex是互斥锁。
p数组是N个semaphore代表哲学家。
captain方法,检查特定的哲学家当前状态是否是HUNGRY,且左右两侧的哲学家都不在进餐,如果都符合就通知这位哲学家进餐。
评价:该方案不是最好的方案,可以google到更多有趣的解法。
小结:
由上述两个例子可以看出,semaphore不仅可以作为互斥锁,更重要的是,它能起到通知作用,从而解决系统的同步问题。
问题关键:
生产者与消费者共同使用的队列大小有限,生产者不能过快地生产导致队列溢出,消费者不能无限消费导致消费了NULL。
要求:
1. 如果队列满了,生产者必须等待;消费者每次消费完一个产品,都应该及时通知生产者。
2. 如果队列空了,消费者必须等待;生产者每次生产一个产品,都应该及时通知消费者。
用semaphore实现:
分析:
使用了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 有限等待” 原则。
一种可行方案:
改变上述方案的思路,将重点放在哲学家而不是筷子上,即一位哲学家进餐不是检查左右侧的筷子是否可用,而是检查左右侧的哲学家是否正在进餐。最后,引入一位"服务员",帮助通知哲学家进餐时机。
state数组存放的是哲学家的状态,包含 HUNGRY, EATING, THINKING三种状态。
mutex是互斥锁。
p数组是N个semaphore代表哲学家。
captain方法,检查特定的哲学家当前状态是否是HUNGRY,且左右两侧的哲学家都不在进餐,如果都符合就通知这位哲学家进餐。
评价:该方案不是最好的方案,可以google到更多有趣的解法。
小结:
由上述两个例子可以看出,semaphore不仅可以作为互斥锁,更重要的是,它能起到通知作用,从而解决系统的同步问题。
相关文章推荐
- Scala 深入浅出实战经典 第98讲:使用SBT开发时动手解决rt.jar中CharSequence is broken等问题
- 经典的c++下面使用pthread_create问题的解决
- 【读书笔记】linux系统用semaphore来解决经典的生产者-消费者问题
- Java使用for循环解决经典的鸡兔同笼问题示例
- 汉诺塔问题是使用递归解决问题的经典范例。
- 经典IPC问题-哲学家就餐分析与解决
- 在WEB程序中使用.NET Remoting的IpcChannel时注意事项(关于“拒绝访问”问题的解决)
- 彻底解决RedHat8下的Kylix3安装使用的问题(安装、字体显示、bcb编译问题)
- 使用dbms_rectifier_diff解决高级复制中的数据冲突问题
- 使用面向对象技术解决商品打折问题(二)
- 解决使用ASP无法连接 ORACLE 9i 数据库的问题。
- 在sps中使用第三方smtp软件解决邮件服务器不允许匿名访问的问题
- 使用webservice解决多系统登陆问题(收藏)
- 关于在struts 框架中使用Filter过滤器解决汉字编码问题
- 在使用BizTalk时遇到一个很郁闷的问题 之解决篇
- 使用内存DC解决重画闪烁问题
- 使用word的com组件解决读取时乱码的问题
- 水晶报表使用经验谈4--使用视图解决在报表中的多表关联问题
- 使用Apache Axis部署 Web服务时的常见问题及其解决方法
- 蛙蛙推荐:使用FreeTextBox出现脚本错误的问题解决