经典的IPC问题
Inter-Process Communication的缩写,含义是进程间通信,是指两个进程间交换数据的过程。
哲学家进餐问题
概述
- 哲学家进餐/思考
- 进餐需要两把叉子
- 每次拿一把叉子
- 如何预防死锁
问题简介
哲学家的生活包括两个不同的阶段:吃饭和思考
当一个哲学家觉得饿时,他就试图去取他左边和右边的叉子,每次拿一把,但是部分次序,如果成功地获得了两把叉子,他就吃一会儿,然后放下叉子继续思考。
关键的问题就是:为每个哲学家写一段程序来描述其行为而且不能思索,你可以做到吗?
一种不正确的解法
#define N 5 //哲学家的数目
void philosopher(int i) { //i是哲学家的编号,从0到4
while (true) {
think(); //哲学家正在思考
take_fork(i); //取左边的叉子
take_fork((i + 1) % N); //取右面叉子:%表示取模运算
eat(); //空心粉味道不错
put_fork(i); //把左面叉子放回桌子
put_fork((i + 1) % N) //把右面叉子放回桌子
}
}
但是当所有哲学家同时拿起左边的叉子,无法得到右边的叉子——死锁
程序稍作修改:所有的哲学家都同时拿起左叉,看到右叉不可用,又都放下左叉,等一会儿,又同时拿起左叉,如此这般,永远重复。对于这种情况,即所有的程序都在无限期地运行,但是都无法取得任何进展,就成为饥饿(starvation)。
对上例算法可做一点改进,它既不会死锁也不会饥饿:即,使用一个二进制信号量对五个think
之后的语句进行保护。在开始拿叉子之前,哲学家先对信号量mutex
执行down
操作。在放回叉子后,他要对mutex
执行up
操作。
从理论上讲,该解法是可行的。但是从实力角度来看,有性能上的缺陷:任意时刻只能有一个哲学家进餐。而五把叉子实际上允许有两位哲学将同时进餐。
解法
#define N 5 /* 哲学家数目 */
#define LEFT (i+N-1)%N /* i的左邻编号 */
#define RIGHT (i+1)%N /* i的右邻编号 */
#define THINKING 0 /* 哲学家在思考 */
#define HUNGRY 1 /* 哲学家试图拿起叉子 */
#define EATING 2 /* 哲学家进餐 */
typedef int semaphore; /* 信号量 */
int state[N]; /* 记录每位哲学家状态 */
semaphore mutex = 1; /* 临界区的互斥 */
semaphore s[N]; /* 每位哲学家一个信号量 */
/* i: 哲学家编号,从0到N-1 */
void philosopher(int i) {
while (TRUE) { /* 无限循环 */
think(); /* 哲学家思考 */
take_forks(i); /* 需要两个叉子, */
eat(); /* 哲学家进餐 */
put_forks(i); /* 将叉子放回到桌子上 */
}
}
void take_forks(int i) {
down(&mutex); /* 进入临界区 */
state[i] = HUNGRY; /* 记录哲学家i处于饥饿状态 */
test(i); /* 尝试获取两把叉子 */
up(&mutex); /* 退出临界区 */
down(&s[i]); /* 如果得不到需要的叉子则阻塞 */
}
void put_forks(i) {
down(&mutex); /* 进入临界区 */
state[i] = THINKING; /* 哲学家进餐完毕 */
test(LEFT); /* 测试左邻是否可以吃 */
test(RIGHT); /* 测试右邻是否可以吃 */
up(&mutex); /* 离开临界区 */
}
void test(i) {
//我是饥饿的但是左右都不再吃的时候
if (state[i] == HUNGRY && state[LEFT] != EATING && state[RIGHT] != EATING) {
state[i] = EATING;
up(&s[i]);
}
}
上面给出的解法是没有死锁的,而且对于任意多位哲学家的情况都能获得最大的并行度。它使用一个数组state
来记录哲学家是在吃饭、思考还是饿了。一个哲学家只有在两个邻座都不在进餐时,才允许转换到进餐状态。哲学家i的邻居是由宏LEFT
和RIGHT
定义。
该程序使用了一个信号量数组,每个信号量对应于一位哲学家,这样,所需的叉子被占用时,饥饿的哲学家就可以被阻塞。注意每个进程将历程philosopher
作为朱代码运行,而其他例程,如take_forks
、put_forks
和test
都只是普通的例程,而不是单独的进程。
读者/写者问题
另一个著名的问题是读者—写者问题,它建模了对数据库的访问。
例如,设想一个飞机定票系统,其中有许多竞争的进程试图读写其中的数据。多个进程同时读是可以接受的,但如果一个进程正在更新数据库,则所有其他进程都不能访问数据库,即使读操作也不行。这里的问题是:如何对读者和写者进行编程?
进程A操作 | 进程B操作 | 是否允许 |
---|---|---|
读 | 读 | 允许 |
读 | 写 | 互斥 |
写 | 写 | 互斥 |
typedef int semaphore;
semaphore mutex = 1; /* 控制对RC的访问 */
semaphore db = 1; /* 控制对数据库的访问 */
int rc = 0; /* 正在读或想要读的进程数 */
void reader(void) {
while (TRUE) { /* 无限循环 */
down(&mutex); /* 排斥对RC的访问*/
rc = rc + 1; /* 又多了一个读者 */
/*如果这是第一个读者,那么......*/
if (rc == 1)
//只要有一个读者在读书编者就不能编书
//当前有进程在读取数据库
down(&db);
up(&mutex); /*恢复对RC的访问*/
read_data_base(); /*访问数据*/
down(&mutex); /*排斥对RC的访问*/
rc = rc - 1; /*读者又少了一个*/
/*如果这是最后一个读者,那么......*/
if (rc == 0)
up(&db);
use_data_read(); /*非临界区操作*/
}
}
void writer(void) {
while (TRUE) {
think_up_data(); /*非临界区操作*/
down(&db); /*排斥访问*/
write_data_base(); /*修改数据*/
up(&db); /*恢复访问*/
}
}
第一个读者对信号量db
执行DOWN
。随后的读者给计数器rc
加1。当读者离开时,它们递减这个计数器,而最后一个读者则对db
执行UP
,这样就允许一个阻塞的写者可以访问数据库。
设想当一个读者在使用数据库时,另一个读者也来访问数据库,由于同时允许多个读者同时进行读操作,所以第二个读者也被允许进入,同理第三个及随后更多的读者都被允许进入。
经典的IPC问题的更多相关文章
- 操作系统之进程篇(4)--经典进程间通信(IPC)问题
1. 哲学家进餐问题: 问题描述: 五个哲学家在一个圆桌上进餐,每人的面前放了一盘意大利面,两个盘子之间有一个叉子,但是由于盘子里面的面条十分光滑,需要两个叉子才能进行就餐行为.餐桌的布局如下图所示: ...
- #干货#小微信贷风控中类IPC模式和集中审批模式
浅析小微信贷风控中类IPC模式和集中审批模式 席占斌 常言道瑕不掩瑜,反过来讲瑜自然也不能掩瑕,看问题需要客观公正辩证. 在小微信贷中,风控模式依旧是核心,目前比较流行和占比较大的风控模式有很经典的I ...
- 一次完整的从webshell到域控的探索之路
前言 内网渗透测试资料基本上都是很多大牛的文章告诉我们思路如何,但是对于我等小菜一直是云里雾里. 于是使用什么样的工具才内网才能畅通无阻,成了大家一直以来的渴求. 今天小菜我本着所有师傅们无私分享的精 ...
- Metasploit域渗透测试全程实录(终结篇)
本文作者:i春秋签约作家——shuteer 前言 内网渗透测试资料基本上都是很多大牛的文章告诉我们思路如何,但是对于我等小菜一直是云里雾里.于是使用什么样的工具才内网才能畅通无阻,成了大家一直以来的渴 ...
- python多进程-----multiprocessing包
multiprocessing并非是python的一个模块,而是python中多进程管理的一个包,在学习的时候可以与threading这个模块作类比,正如我们在上一篇转载的文章中所提,python的多 ...
- Linux 进程间通信(一)(经典IPC:消息队列、信号量、共享存储)
有3种称作XSI IPC的IPC:消息队列.信号量.共享存储.这种类型的IPC有如下共同的特性. 每个内核中的IPC都用一个非负整数标志.标识符是IPC对象的内部名称,为了使多个合作进程能够在同一IP ...
- Linux 进程间通信(一)(经典IPC:管道、FIFO)
管道 管道是Unix系统IPC的最古老方式,有两种局限性: (1) 历史上它们是半双工的(即数据只能在一个方向上流动),虽然现在某些系统提供了全双工管道,但是为了可移植性,不要抱有绝对的全双工假设 ...
- Classic IPC Problems 经典的进程间通信问题
The Producer-Consumer Problem Presenter Notes: 生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bo ...
- IPC 经典问题:Reader & Writer Problem
完整代码实现: #include <stdio.h> #include <unistd.h> #include <time.h> #include <stdl ...
随机推荐
- Django框架07 /cookie和session
Django框架07 /cookie和session 目录 Django框架07 /cookie和session 1. django请求生命周期 2. cookie 3. session 4. 总结 ...
- dataframe一次小实验
老师搞不清,一个ndarray[df['columns']==a],返回的是什么,目前看来应该是df[] == a 的索引
- 使用QtCreator遇到的一些问题
0. 背景 最近在学习QtCreator(版本:4.8.1:编译器:MSVC 2017 64-bit),遇到了一些问题,特记录如下.( 1. 引用库 QtCreator可以直接包含Windows.h, ...
- DEX文件解析--7、类及其类数据解析(完结篇)
一.前言 前置技能链接: DEX文件解析---1.dex文件头解析 DEX文件解析---2.Dex文件checksum(校验和)解析 DEX文件解析--3.d ...
- 集训作业 洛谷P1101 单词方阵
这个题的长度真的有点长,我直接放图片吧 这个题又是一个和谐的搜索,找到yizhong的y就开始8面搜索,遇见正确的字母就继续搜索,不正确就果断放弃,果然又是一个和谐的搜索呢. #include< ...
- 手把手撸套框架-ORM框架的选择
目录 一,为什么选择SqlSugar? 在.net core ORM框架中,能选择的方案其实有很多,包括以下方案: 1,EF-Core 2,Dapper 3,FreeSql 4,SqlSugar 为什 ...
- ztree : checkbox 选中/不选中时动态添加/删除DOM元素
先上代码. var IDMark_Switch = "_switch", IDMark_Icon = "_ico", IDMark_Span = "_ ...
- layui 数据表格自带的导出Excel,身份证等E+/000问题解决
layui数据表格的工具栏自带导出Excel 会将身份证等 长整数的 自动变成E+并且 后面有000.从而导致数据不能完整导出. 解决方案: 1.先下载Excel的插件包.将压缩包内的两个js放到 l ...
- 利用华为eNSP模拟器实现vlan之间的通信
eNSP交换机配置VLAN 1. 搭建网络拓扑结构 运行eNSP>新建拓扑>搭建如下图的拓扑结构>启动设备.利用调色板将划分的vlan进行区分. 2. pc机IP地址配置 pc1的I ...
- Spark入门(第1讲)
一.Spark是什么 引用官方文档的一句话 Apache Spark is a unified analytics engine for large-scale data processing. Ap ...