经典IPC问题
1.The Dining Philosophers Problem哲学家就餐问题
哲学家的生活中有两种交替活动时段:即吃饭和思考。当一个哲学家觉得饿了时,他就试图分两次去取其左边和右边的叉子,每次拿一把,但不分次序。如果成功地得到了两把叉子,就开始吃饭,吃完后放下叉子继续思考。关键问题是:能为每一个哲学家写一段描述
其行为的程序,且决不会死锁吗?
#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]; //每个哲学家一个信号量
void philosopher(int i) //哲学家编号:从0到N-1
{
while(true){ //无限循环
}
}
void take_forks(int i) //哲学家编号,从0到N-1
{
//下面的这组down up操作是对test进行保护的
down(&mutex);
state[i] = HUNGRY;
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]);
}
}
2.The Readers and Writers Problem读写者问题
多个读者同时读:可以接受
一个写者在写,读者想读,其他写者想写:都不允许
typedef int semaphore;
semaphore mutex = 1; //控制对rc的访问
semaphore db = 1; //控制对数据库的访问
int rc = 0;
void reader(void)
{
while(TRUE){
down(&mutex); //获得对rc的互斥访问
rc = rc + 1; //读者数+1
if(rc == 1)down(&db); //如果是第一个读者,那么进入写,获得了数据库的访问,那么写者将不再能进入数据库写数据
//如果此时已经有写者在写了,第一个读者将会阻塞在这里,后续的读者将会阻塞在第9行
up(&mutex); //其他的读者就可以进入的
read_data_base(); //访问数据
down(&mutex); //读者读完再次进入关键区,获得rc的访问权
rc = rc - 1; //读者读完,读者数-1
if(rc == 0)up(&db); //如果这是最后一个读者,那么唤醒可能阻塞的写者
up(&mutex); //离开对rc的互斥访问
use_data_read(); //非临界区
}
}
void writer(void)
{
while(true){
think_up_data(); //非临界区
down(&db); //写者写的时候任何线程都不能进入
write_data_base(); //在关键区内进行写操作
up(&db); //写完,释放互斥访问
}
}
这里的rc和数据库访问都是关键区,需要进行互斥访问,所以一旦要对这两个资源进行修改,就要进行相应的down 和 up操作。所以使用一个mutex用来实现对rc的互斥访问,用db来实现对data_base的互斥访问。特别的是,在没有写者时,读者之间对data_base的访问是不需要互斥的。
rc的互斥访问比较简单,这里详细说明一下第11行if(rc == 1)down(&db);
的作用:这里不仅是让第一个读者进入去,后续的写者没有办法再进入关键区,但后学的第二个第三个由于不满足rc==1而不受影响;更重要的是,这句代码实现了写者访问关键区时,读者将不再能访问关键区——后面假如有读者,第一个读者会被阻塞在第11行的down(&db)
,而第二个读者,第三个读者将会因为第一个读者无法进行up(&mutex)
而阻塞在第9行down(&mutex)
。所以11行的代码是理解这个问题的关键。
在上述的程序中允许多个读者一起访问数据库。同时上述的写法也是读者优先的,只要数据库中还有读者在读,就算一个写者在后来的读者前等待,那么后来的读者可以访问数据库,但是写者不行。数据库中存在读者,写者就没有写的机会,假如读者读的时间>到达的时间,比如读者读完要花费5秒,下一个读者以每2s一个的频率到来,那么等待中的写者将永远没有写的机会。