IPC经典问题
读者写者问题
读者优先:
semaphore mutex=1;//控制对rc的访问
semaphore db=1;//控制对数据库的访问
int rc=1;//正在读或想要读的进程数
void reader(void)
{
while(1){
down(&mutex);
rc++;
if(rc==1)
down(&db);
up(&mutex);
read_database();
down(&mutex);
rc--;
if(rc==0)
up(&db);
up(&mutex);
use_data_read();
}
}
void writer(void)
{
while(1){
think_up_data();
down(&db);
write_database();
up(&db);
}
}
写者优先,条件为:
(1)多个读者可以同时进行读;
(2)写者必须互斥(只允许一个写者写,同时也不能读者、写者同时进行);
(3)写者优先于读者(一旦有写者来,则后续读者必须等待,唤醒时优先考虑写者)。
注意唤醒时优先考虑写者这个条件
semaphore read=1;//用于阻塞读者
semaphore rmutex=1,wmutex=1;//用于控制对rcount和wcount的访问
semaphore db=1;//控制对数据库的访问
int rcount=wcount=0;
void reader(void)
{
p(read); //只要有写者等待,读者就会阻塞
p(rmutex);
rcount++;
if(rcount==1)
p(db);
v(rmutex);
v(read);//及时释放,多个读者可以同时读
read_database();
p(rmutex);
rcount--;
if(rcount==0)
v(db);
v(rmutex);
}
void writer(void)
{
p(wmutex);
wcount++;
if(wcount==1)
p(read);
v(wmutex);
p(db);
write_database();
v(db);
p(wmutex);
wcount--;
if(wcount==0)
v(read);
v(wmutex);
}
如果唤醒时读写队列平等的话
semaphore write=1;//用于阻塞写者
semaphore mutex=1;//用于控制对rc的访问
semaphore db=1;//控制对数据库的访问
int rc=0;
void reader(void)
{
p(db);
p(mutex);
rc++;
if(rc==1)
p(write); //有读者进入,互斥写操作
v(mutex);
v(db); // 及时释放读写互斥信号量,允许其它读、写进程申请资源
read_database();
p(mutex);
rc--;
if(rc==0)
v(write); //所有读者退出,允许写操作
v(mutex);
}
void writer(void)
{
p(db);// 互斥后续其它读者、写者
p(write);//如有读者正在读,等待所有读者读完
write_database();
v(write);//允许后续新的第一个读者进入后互斥写操作
v(db);//允许后续新读者及其它写者
}
哲学家就餐问题
注意状态的变化应该处于临界区,如果一个哲学家不能拿起叉子时应阻塞,
同时加入一个状态表明他饥饿,旁边的哲学家就餐完毕会通知他
#define N 5
#define LEFT (i-1)%N
#define RIGHT (i+1)%N
#define THINKING 0
#define HUNGRY 1
#define EATING 2
int state[N];//记录每个人状态的数组
semaphore mutex=1;//临界区互斥
semaphore s[N]={0};//每个哲学家一个信号量,表示能否得到两只叉子
void philosopher(int i)
{
while(1){
think();
take_forks(i);
eat();
put_forks(i);
}
}
void take_forks(int i)
{
donw(&mutex);
state[i]=HUNGRY;
test(i);//试图得到两只叉子
up(&mutex);
down(&s[i]);//如果得不到叉子就阻塞
}
void put_forks(int i)
{
down(&mutex);
stata[i]=THINKING;
test(LEFT);//看下左邻居现在是否能进餐
test(RIGHT);//看下右邻居现在是否能进餐
up(&mutex);
}
void test(int i)
{
if(state[i]==HUNGRY && state[LEFT]!=EATING && state[RIGHT]!=EATING){
state[i]=EATING;
up(&s[i]);
}
}
红黑客过河
对同步与互斥的分析:
同步关系:1. 满员才能开船;2. 红黑客满足一定的组合规则,才能有四人上船
互斥关系:红黑客对请求上船的控制
显然,此题难点在对同步关系的解决。
下面给出所写程序的算法思想:
Red():每个红客到来请求上船时执行该程序:
1.请求进入临界区;
2.首先检查本人的到来是否满足上船的组合(即4个红客或2个红客与2个黑客);
3.如果满足2个红客和2和黑客的组合,则看是否有船可上,有的话该红客上船并通知另外1个红客和2个黑客上船,然后通知船满员,并退出临界区;
4.如果满足4个红客的组合,则看是否有船可上,有的话该红客上船并通知另外3个红客上船,然后通知船满员,并退出临界区;
5.不符合上船的组合,则先退出临界区,然后在信号量S_red上等待,直到当条件满足时,有人通知其上船。
6.完毕。
Black():每个黑客到来请求上船时执行该程序,其算法与Red()完全一致;
Boat():河上的船执行该程序:
1.等待满员后开船过河;
2.空船返回,通知可以上船了,转而执行1。
semapore boats=1; //河上船只的数量
semapore full=0; //船的满员状态
semapore S_red=0; //控制红客上船
semapore S_black=0; //控制黑客上船
semapore mutex=1; //由于互斥
int reds=0; //等待上船的红客数
int blacks=0; //等待上船的黑客数
Red()
{
P(mutex);//进入临界区
reds++; //等待上船的红客数加1
if(reds >=2 && blacks >=2)
{//2个红客和黑客的组合
P(boats); //准备上船,无船则等待
take_boat();//该红客上船
reds=reds-2;//等待上船的红客数减2
V(S_red); //通知另一个红客上船
blacks=blacks-2;//等待上船的黑客数减2
//通知其他两黑客上船
V(S_black);
V(S_black);
V(full);//通知船满员
V(mutex);//退出临界区
}
else if(reds==4)
{//4个红客的组合
P(boats); //准备上船,无船则等待
take_boat(); //该红客上船
//递减等待上船的红客数,通知其他3个红客上船
while(--reds)
V(S_red);
V(full);//通知船满员
V(mutex);//退出临界区
}
else
{
V(mutex);//退出临界区,此步必在P(S_red)之前,不然会产生死锁
//该红客等待直至条件满足时上船
P(S_red);
take_boat();
}
}
Black()
{
P(mutex);
blacks++;
if(blacks >=2 && reds >=2)
{
P(boats);
take_boat();
blacks=blacks-2;
V(S_black);
reds=reds-2;
V(S_red);
V(S_red);
V(full);
V(mutex);
}
else if(blacks==4)
{
P(boats);
take_boat();
while(--blacks)
V(S_black);
V(full);
V(mutex);
}
else
{
V(mutex);
P(S_black);
take_boat();
}
}
Boat()
{
while(TRUE){
P(full); //等待满员
shove_off(); //开船过河
boat_return();//空船返回
V(boats); //通知可以上船了
}
}
该算法存在一个问题是如果2红1黑时接下来来的都是红客时,会造成饥饿现象。
改进:利用5人中必有4人满足开船条件,每5个人检查一下让其中4个人过河,红黑客算法也不用分开写了。