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