问题描述:
一条河上有N个桥墩组成的桥,过河的人只能沿着桥向前走而不能向后退,桥墩一次只能站一个人。过河时,只要对岸无人过,就可以过。但不允许河对岸的两个人同时过,以防止出现死锁。给出两个方向的人顺利过河的同步算法。
问题分析:
解决此问题之前,要先了解读者写者问题。
题意分析需要保证:
- 同一时刻两个方向只能有一个方向的人再前进。
- 只要方向1上还有人未通过,则方向2的人就不能上桥。
- 同一个方向上能有多个人等待过桥,但是每次只能过一个人,其他人可以排队。
- 方向2的人想上桥通过,必须等方向1的全部人都通过才可以。反之也成立。
通过上述分析我们不难发现,过桥问题实际就是读者写者的读者优先算法的一个变形。
- 只能有一个方向的人过桥,等价于读者与写者只能有一种人在工作。通过互斥信号量解决二者之间的互斥关系。过桥问题通过mutex来实现两个方向上的互斥,mutex设置为1,表示将方向锁定。
- 任意一个方向都有可能有很多人,所以设置count1/2变量来对每个方向上的人进行计数,只有第一个上桥的人才需要对方向上锁,最后一个离开桥的人对方向解锁。类比读者写者问题,只有第一个读者才需要对读写进程进行加锁,只有最后一个读者才对读写进程进行解锁。都是通过count变量来实现。
- 依据双标志先检查法的不足,如果检查和上锁不是一气呵成的,则可能会违法忙则等待,同一时刻有多个进程进入临界区。因此必须设置一个互斥信号量来保证对检查和上锁一气呵成,因此出现了Scount1/2信号量,保证对对应的count变量的检查和上锁是一气呵成的。
- 由于有n个桥墩,每个人只能站一个,因此最多允许一个方向上的N个人申请,所以共享变量Scount=N。
此处不再区分到底是哪个方向优先问题,两个方向的优先级是通过哪一个先抢占处理机来决定的,并非人为决定。
代码:
Semaphore
mutex=1, //对方向锁定的互斥信号量
scount1=1, //确保方向1对count1的检查和上锁是原子操作
scount2=1, //确保方向2对count2的检查和上锁是原子操作
scount=N; //一共有多少个桥墩
int
count1=0, //1方向上有多少人
count2=0; //2方向上有多少人
//方向1
void direct1(int i)
{
wait(scount1);
if(count1==0)
wait(mutex);
count1++;
signal(scount1);
wait(scount);
上桥,过桥,下桥;
signal(scount);
wait(scount1);
count1--;
if(count1==0)
signal(mutex);
signal(scount1);
}
//方向2
void direct2(int i)
{
wait(scount2);
if(count2==0)
wait(mutex);
count2++;
signal(scount2);
wait(scount);
上桥,过桥,下桥;
signal(scount);
wait(scount2);
count2--;
if(count2==0)
signal(mutex);
signal(scount2);
}
//main执行
main()
{
cobegin{
direct1(1);
…
direct1(n);
direct2(1);
…
direct2(m);
}
}