1. 读者——写者问题
动机
- 共享数据的访问
两种类型使用者
- 读者:不需要修改数据
- 写者:读取和修改数据
问题的约束
- 允许同一时间有多个读者,但在任何时候只有一个写者
- 当没有写者时读者才能访问数据
- 当没有读者和写者时写者才能访问数据
- 在任何时候只能有一个线程可以操作共享变量
多个并发进程的数据集共享
- 读者–只读数据集;他们不执行任何更新
- 写者–可以读取和写入
共享数据
- 数据集
- 信号量CountMutex初始化为1
- 信号量WriteMutex初始化为1
- 整数Rcount初始化为0
情况一: 读者优先
情况二: 写者优先
基于读者优先策略的方法,只要有一个读者处于活动状态,后来的读者都会被接纳。如果读者源源不断地出现的话,那么写者就始终处于阻塞状态。
基于写者优先策略的方法:一旦写者就绪,那么写者会尽可能快地执行写操作。如果写者源源不断地出现的话,那么读者就始终处于阻塞状态。
使用管程实现写者优先
2. 哲学家就餐问题
问题描述:(1965年由Dijkstra首先提出并解决)5个哲学家围绕一张圆桌而坐,桌子上放着5支叉子,每两个哲学家之间放一支;哲学家的动作包括思考和进餐,进餐时需要同时拿起他左边和右边的两支叉子,思考时则同时将两支叉子放回原处。如何保证哲学家们的动作有序进行?如:不出现有人永远拿不到叉子;
共享数据
- Bowl of rice (data set)
- Semaphore fork [5] initialized to l
take_fork(i) : P(fork[i])put_fork(i) : v(fork[i])
思路⑴ 哲学家自己怎么来解决这个问题?
指导原则:要么不拿,要么就拿两把叉子。
S1思考中…
S2进入饥饿状态;
S3如果左邻居或右邻居正在进餐,等待;否则转S4
S4拿起两把叉子;
S5吃面条…
S6放下左边的叉子;
S7放下右边的叉子;
S8新的循环又开始了,转S1
思路(2计算机程序怎么来解决这个问题?
指导原则:不能浪费CPU时间;进程间相互通信。
S1思考中…
S2进入饥饿状态;
S3如果左邻居或右邻居正在进餐,进程进入阻塞态;否则转S4
S4拿起两把叉子;
S5吃面条…
S6放下左边的叉子,看看左邻居现在能否进餐(饥饿状态、两把叉子都在)。若能则唤醒之;
S7放下右边的叉子,看看右邻居现在能否进餐.(饥饿状态、两把叉子都在),若能,唤醒之;
S8新的一天又开始了,转S1
思路(3)怎么样来编写程序﹖
1.必须有数据结构,来描述每个哲学家的当前状态;
2.该状态是一个临界资源,各个哲学家对它的访问应该互斥地进行一一进程互斥;
3.一个哲学家吃饱后,可能要唤醒它的左邻右舍,两者之间存在着同步关系—―进程同步;
1.必须有一个数据结构,来描述每个哲学家的当前状态;
#define N 5 //哲学家个数 #define LEFT i //第i个哲学家的左邻居 #define RIGHT (i+1)%N //第i个哲学家的右邻居 #define THINKING 0 //思考状态 #define HUNGRY 1 //饥饿状态 #define EATING 2 //进餐状态 int state[N]; //记录每个人的状态
2.该状态是一个临界资源,对它的访问应该互斥地进行
semaphore mutex; //互斥信号量,初值1
3.一个哲学家吃饱后,可能要唤醒邻居,存在着同步关系
semaphore s[N]; //同步信号量,初值0
函数一: philosopher
函数2:take_forks
函数3:test_take_left_right_forks
函数4:put_forks