struct Semaphore{
int value;
queue process;
};
吃水果问题
问题描述:
桌子上有一只盘子,每次只能放一个水果,爸爸专向盘中放苹果,妈妈专向盘中放桔子,儿子专吃盘里的桔子,女儿专吃盘里的苹果.只要盘子空,则爸爸或妈妈可以向盘中放水果,仅当盘中有自己需要的水果时,儿子或女儿可从中取出.
//分析:
//首先爸爸,妈妈,儿子,女儿的动作都不一样,所以应当有四个进程
//一家人都是互斥的访问盘子,需要一个互斥变量
//爸爸女儿同步,需要两个同步变量
//妈妈儿子同步,需要两个同步变量
//只要盘子空,则爸爸妈妈可向盘中放水果,说明盘子中只会有一个水果,所以是单缓冲问题
struct Semaphore Empty//盘子空位信号量
{
value = 1;//初始情况盘子有一个空位
P=PapMom;//用于存放因为盘子没有空位而阻塞的爸爸妈妈进程
};
struct Semaphore FullApple//盘子中苹果信号量
{
value = 0;//初始情况盘子中没有苹果
P=daughter;//用于存放因为盘子没有苹果阻塞的女儿进程
}
struct Semaphore FullOrange//盘子中桔子信号量
{
value = 0;//初始情况盘子中没有桔子
P=son;//用于存放因为盘子没有桔子阻塞的儿子进程
}
void Pap()
{
P(Empty);//判断盘子是否为空
//放苹果的代码
V(FullApple);//唤醒女儿进程
}
void Mom()
{
P(Empty);//判断盘子是否为空
//放桔子的代码
V(FullOrange);//唤醒儿子进程
}
void Son()
{
P(FullOrange);//判断盘子是否有桔子
//拿桔子的代码
V(Empty);//唤醒爸爸或者妈妈
}
void Daughter()
{
P(FullApple);//判断盘子是否有苹果
//拿苹果的代码
V(Empty);//唤醒爸爸或者妈妈
}
司机-售票员问题
设公共汽车上,司机和售票员的活动分别是:
司机:
启动车辆
正常停车
到站停车
售票员:
上下乘客
关车门
售票
开车门
上下乘客
在汽车不断到站,停车,行驶过程中,这两个活动的同步关系.
//分析:
//司机和售票员的动作不同,所以有两类进程
//司机和售票员有同步关系,所以需要两个同步信号量
struct Semaphore SJAction//控制司机行动的信号量
{
value = 0;//最初情况是司机不动
queue SJ;//用于存放因为司机不动而阻塞的司机进程
};
struct Semaphore SPYAction//控制售票员行动的信号量
{
value = 1;//最初情况是售票员动
queue SPY;//用于存放因为售票员不动而阻塞的售票员进程
};
void SJ()
{
P(SJAction);
//启动车辆,正常行车,到站停车代码
V(SPYAction);
}
void SPY()
{
P(SPYAction);
//上下乘客
//关车门
V(SJaction);
//售票
P(SPYAction);
//开车门,上下乘客
V(SJaction);
}
和尚打水问题
某寺庙,有小和尚和老和尚若干,有一个水缸,由小和尚提水入缸供老和尚饮用.水缸可以容纳10桶水,水取自同一口井,由于水井中,由于水井口窄,每次只能容纳一个水桶取水.水桶总数为3个.每次入水,取水仅为一个桶,且不可同时进行.
//分析:
//小和尚老和尚动作不同,所以有两类进程
//小和尚老和尚互斥拿桶,需要一个互斥信号量
//小和尚老和尚互斥入缸,需要一个互斥信号量
//小和尚互斥取水,需要一个互斥信号量
//小和尚老和尚同步从水缸中取水,需要两个同步信号量信号量
struct Semaphore T//临界资源桶的信号量
{
value = 3;//起初有三个桶
queue Monk;//用于存放因为没有桶而阻塞的进程
}
struct Semaphore G//临界资源缸的访问权
{
value = 1;//起初有一个缸
queue Monk;//用于存放因为不能用缸而阻塞的进程
}
struct Semaphore J//临界资源井的访问权
{
value = 1;//起初有一个井
queue Monk;//用于存放因为不能用井而阻塞的进程
}
struct Semaphore Full//缸中有几桶水的信号量
{
value = 0;//缸中起初有0桶水
queue OldMonK;//用于存放因为没有水而阻塞的老和尚进程
}
struct Semaphore Empty//缸中有几个空位的信号量
{
value = 10;//缸中起初由10个空位
queue LittleMonk;//用于存放因为没有空位而挂起的小和尚进程
}
void OldMonk()
{
P(Full);
P(T);
P(G);
//取水的代码
V(G);
V(T);
V(Empty);
}
void LittleMonk()
{
P(Empty);
P(T);
P(J);
//从井里取水的代码
P(G);
//往缸里倒水的代码
V(G);
V(J);
V(T);
V(Full);
}
问题描述:
在南开大学和天津大学之间有一条弯曲的小路,其中从S到T一段路每次只允许一辆自行车通过,但中间有一个小的“安全岛”M(同时允许两辆自行车停留),可供两辆自行车已从两端进入小路情况下错车使用,如图所示.试设计一个算法来使来往的自行车均可顺利通过.
//分析:
//南开大学到天津大学(N2T)和从天津大学到南开大学(T2N)的动作不同,所以分为两类进程
//路段是N2T和T2N互斥使用的,所以需要一个互斥信号量
//N2T之间T2N之间并不互斥的使用路段,所以需要两个记录,为了实现这两个记录,所以还需要两个互斥信号量
//由于M的特殊性,N2T(T2N)的第二个进程才会将T2N(N2T)锁住,最后一个进程在路过M时就可以释放对T2N(N2T)的锁
struct Semaphore Way//这段路的访问权限信号量
{
value = 1;//这段路最初是可以访问的
p = process;//用于存储因为无法访问这段路而阻塞的进程
}
struct Semaphore N2TQuery//从南开大学到天津大学的自行车数量记录的访问权限信号量
{
value = 1;//这个记录起初是可以访问的
p = N2T;//用于存储因为无法访问这个记录而阻塞的从南开大学到天津大学的自行车进程
}
struct Semaphore T2NQuery//从天津大学到南开大学的自行车数量记录的访问权限信号量
{
value = 1;//这个记录起初是可以访问的
p = T2N;//用于存储因为无法访问这个记录而阻塞的从天津大学到南开大学的自行车进程
}
int N2Tcount = 0;
int T2Ncount = 0;
void N2T()
{
P(N2Tquery);//N2T判断是否可以访问记录
if(N2Tcount==0){//如果是第一辆N2T的自行车
//行驶到M处的代码
}
if(N2Tcount==1){//如果是第二辆N2T的自行车
P(Way);//判断路段是否还可以访问
}
N2Tcount++;//路段中的N2T自行车+1
V(N2Tquery);//N2T自行车的数量可以变化了
//自行车行驶的代码
P(N2Tquery);//判断是否可以访问记录
//可完善处:实际上,在最后一辆N2T自行车经过M处时,如果M处的T2N有自行车,那么它已经可以被唤醒了,但是一旦唤醒了这条路段,那么第二辆T2N自行车如果也进入路段,而最后一辆N2T自行车还没有离开路段,就会导致死锁.
N2Tcount--;//路段中N2T自行车-1
if(N2Tcount==0){
V(Way);//释放对路段的锁
}
V(N2Tquery);
}
void N2T()
{
P(T2Nquery);//判断是否可以访问记录
if(T2Ncount==0){//如果是第一辆T2N的自行车
//行驶到M处的代码
}
if(T2Ncount==1){//如果是第二辆T2N的自行车
P(Way);//判断路段是否还可以访问
}
T2Ncount++;//路段中的T2N自行车+1
V(T2Nquery);//T2N自行车的数量可以变化了
//自行车行驶的代码
P(T2Nquery);//判断是否可以访问记录
//可完善处:实际上,在最后一辆T2N自行车经过M处时,如果M处的N2T有自行车,那么它已经可以被唤醒了,但是一旦唤醒了这条路段,那么第二辆N2T自行车如果也进入路段,而最后一辆T2N自行车还没有离开路段,就会导致死锁.
T2Ncount--;//路段中T2N自行车-1
if(T2Ncount==0){
V(Way);//释放对路段的锁
}
V(T2Nquery);
}