理发师睡觉问题.
//理发店由等待间(包含N个等待座位)和理发间(包含一把理发椅)
//构成。无顾客时,理发师睡觉;当顾客进入理发店发现理发师睡
//觉时,则唤醒理发师。
const int seat=N; //表示N个等待座位
//信号量设置如下:
semaphore customer=0;
semaphore mutex=1;
semaphore CutSeat=1;
int Waiting=0;
Barber()
{
while(true)
{
wait(customer); //理发师查看有无顾客
wait(mutex); //保证对于Waiting变量的互斥访问
Waiting--;
signal(mutex);
CuttingHair(); //开始理发
signal(CutSeat); //释放理发位
}
}
Customer()
{
while(true)
{
wait(mutex); //保证对Waiting的互斥访问
if(Waiting<seat) //判断是否还有座位
{
Waiting++;
signal(mutex);
signal(customer); //增加顾客信号量
wait(CutSeat); //申请理发位
GoToCutSeat(); //前往理发
}
else
{
signal(mutex); //座位已满,离开
}
}
}
喂金鱼问题.
//假设张三和李四共同养一条金鱼,金鱼每天进食一顿,
//所以每天仅且只能喂一次,若超过一次,金鱼胀死,
//若一次都没有喂,金鱼饿死两人都想把金鱼养活,请给
//两人设置喂养金鱼的方式,并用伪代码描述两人行为
//信号量设置如下:
semaphore mutex=1; //保证对于Times的互斥访问
int Times=0;
Three()
{
while(true)
{
wait(mutex); //申请访问Times
if(Times<1)
{
Feeding(); //没喂,就喂
Times=1;
signal(mutex);
}
else
{
signal(mutex); //喂了,很好
}
}
}
//Four()行为一致
Four(){
}
第一读者-写者问题.
//共享的数据集或文件可能在多个进程间被并发访问,因此
//可能有多个读者和写者对其进行操作,一般要求多个读者
//可以同时操作,而读者与写者、多个写者之间的操作应互斥。
//第一读写问题中,读者不会等待,除非写者已经获得了共享
//资源的使用权,这一问题会导致写者饿死。
//信号量设置如下:
semaphore priority=1; //代表读者优先级高于写者
semaphore mutex=1; //互斥访问count
int count=0;
Reader()
{
while(true)
{
wait(mutex);
count++;
if(count==1)
{
wait(priority); //首位Reader需要确定没有Writer
}
signal(mutex);
Reading();
wait(mutex);
count--;
if(count==0)
{
signal(priority);//最后一个Reader需要释放写权限
}
signal(mutex);
}
}
Writer()
{
wait(priority);
Writing();
signal(priority);
}
//存在写者饿死的情况,因为读者进程会计数持续占有priority
//所以只要当前有读者在运行,陆续还有新的读者加入,写者就无法
//获得priority.
第二读者-写者问题.
//针对第一读写问题中的写者饿死状况,第二读写问题中要求
//一旦作者准备就绪,那么作者会尽可能快地执行,换句话说
//如果有一个作者申请访问对象并且正在等待,就不会有新的
//读者能够成功访问共享资源。
//信号量设置如下:
semaphore file=1; //代表共享资源
semaphore priority=1; //代表写者进程优先级高于读者进程
//互斥信号量:
semaphore mutex_W=1;
semaphore mutex_R=1
int Writer=0;
int Reader=0;
Writer()
{
while(true)
{
wait(mutex_W);
Writer++;
if(Writer==1)
{
wait(priority); //第一个写者需要申请优先级信号量
}
signal(mutex_W);
wait(file);
Writing();
signal(file);
wait(mutex_W);
Writer--;
if(Writer==0)
{
signal(priority);//最后一个写者释放优先级信号量
}
signal(mutex_W);
}
}
Reader()
{
while(true)
{
wait(priority); //如果此时有写者正在写或等待
//Reader都无法获得priority
wait(mutex_R);
Reader++;
if(Reader==1)
{
wait(file); //第一个读者申请共享资源
}
signal(mutex_R);
signal(priority);
Reading();
wait(mutex_R);
Reader--;
if(Reader==0)
{
signal(file);
}
signal(mutex_R);
}
}
//存在的问题是读者饿死,因为写者会计数持续占有priority,直到
//最后一个写者进程退出之前,第一个读者永远无法获得priority,
//也就更无法获得file.
读写公平问题.
//1.优先级相同。
//2.写者、读者互斥访问。
//3.只能有一个写者访问临界区。
//4.可以有多个读者同时访问临界资源。
//信号量设置如下:
semaphore file=1;
semaphore priority=1;
//读-写的互斥访问以及写-写互斥,命名出于和第二问题的代码对应
semaphore read=1;
//读者之间互斥访问Reader
int Reader=0;
Writer()
{
wait(priority);
wait(file);
signal(priority);
Writing();
signal(file);
}
Reader()
{
wait(priority);
wait(read);
Reader++;
if(Reader==1)
{
wait(file);
}
signal(read);
signal(priority);
reading();
wait(read);
Reader--;
if(Reader==0)
{
signal(file);
}
signal(read);
}
//注意读写进程都会在自己成功获得file后释放priority,而不是
//上面两种解法中存在一方的持续占有,直到本类型进程为0,这样
//就实现了公平竞争。
- 有关读者写者问题,可以参看这篇文章以相互印证。
哲学家就餐问题.
//1.假设有5个哲学家,所有的时间用来吃饭和思考,他们共
//坐一个圆桌上,每个人坐一把椅子,桌上有5根筷子
//2.当某位哲学家感到饥饿时,他会试图拿桌上的筷子,每次
//只能拿一根,当同时有一双筷子时,他可以吃饭,吃饱后会
//放下两根筷子,开始思考
//3.需要在多个进程之间分配多个资源且不会出现死锁和饿死
//信号量设置如下:
semaphore chopsticks[5]=1;
semaphore mutex=1;
int number=0;
Philosopher_i()
{
while(true)
{
wait(mutex);
number++;
if(number<=4)
{
wait(chopsticks[i]);
wait(chopsticks[(i+1)%5]);
}
signal(mutex);
Eating();
wait(mutex);
number--;
signal(chopsticks[i]);
signal(chopsticks[(i+1)%5])
signal(mutex);
Thinking();
}
}
//可以看出这里的解决方法是,设定变量number,使得最多有4位哲学家
//上桌吃饭,4个进程5个资源,总有一个哲学家能够吃饭,从而不会造
//成死锁。
//其他的解决方法还有:
//1.只有两根筷子同时可用时,才允许哲学家拿筷子;
//2.奇数哲学家先拿左手边的筷子,偶数哲学家先拿起右手边的筷子.
- 有关哲学家问题,可以参看这篇文章了解更多。