经典的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 ...
随机推荐
- mysql练习题99
一.查询每个专业的学生人数 SELECT COUNT(*) FROM student GROUP BY majorid; 二.查询参加考试的学生中,每个学生的平均分.最高分 SELECT avg(sc ...
- 用matplotlib绘制图片示例(新)
test /*! * * Twitter Bootstrap * */ /*! * Bootstrap v3.3.7 (http://getbootstrap.com) * Copyright 201 ...
- web测试中不容忽视的细节
最近在自动化测试的圈子里,我总是碰到很多人在群里和其他地方问为什么这个会出现错误? 为什么这个运行不了?为什么我百度了还是没用? 其实真正的原因可能是你忽略了下面这些需要注意的小地方: 1.页面分辨率 ...
- Qt_IO系统_文件
主要参考: devbean.net 豆子的博客 参考书:<QtCreator 快速入门>第三版 目录 QFile 如何使用QFile QFile 和QFileInfo Demo 文件操作是 ...
- ResNeXt论文阅读笔记.md
目录 1. 提出背景 2. 核心思想 3. 论文核心 4. 分组卷积 5. 核心代码 论文: Aggregated Residual Transformations for Deep Neural N ...
- 【JVM之内存与垃圾回收篇】StringTable
StringTable String的基本特性 String:字符串,使用一对 "" 引起来表示 String s1 = "Nemo"; // 字面量的定义方式 ...
- 【mysql】- 锁篇(上)
回顾 问题 事务并发执行时可能带来各种问题,并发事务访问相同记录的情况大致可以划分为3种 读-读情况:即并发事务相继读取相同的记录 读取操作本身不会对记录有什么影响,并不会引起什么问题,所以允许这种情 ...
- Nginx 服务器配置支持SignalR (WebSocket)
今天SignalR部署在测试环境服务器前端出现无法连接,前端报错如下: failed: Error during WebSocket handshake: Unexpected response co ...
- Win10系统报错问题集锦
收集记录win10的坑 错误1 应用程序-特定 权限设置并未向在应用程序容器 不可用 SID (不可用)中运行的地址 LocalHost (使用 LRPC) 中的用户 NT AUTHORITY\SYS ...
- jQuery中常用网页效果应用
一.常用网页效果应用 1.表单应用 表单由表单标签.表单域和表单按钮组成. 1.1单行文本框应用 例:获取和失去焦点改变样式 首先,在网页中创建一个表单,HTML代码如下 <form actio ...