经典同步问题之哲学家就餐

81 篇文章 2 订阅
65 篇文章 4 订阅
文章探讨了哲学家就餐问题,这是一个经典的并发控制问题。文中提出了三个方案:方案一使用信号量实现,但存在死锁风险;方案二引入互斥量避免死锁,但效率较低;方案三改进了拿叉子的顺序,解决了死锁并提高了效率。
摘要由CSDN通过智能技术生成

一:问题描述

五个哲学家共用一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五只筷子,他们的生活方式是交替的进行思考和进餐。平时,一个哲学家进行思考,饥饿时便试图取用其左右最靠近他的筷子,只有在他拿到左右两只筷子时才能进餐,进餐完毕,放下筷子继续思考。
在这里插入图片描述

那么问题来了,如何保证哲学家们的动作有序进行,而不会有人永远拿不到叉呢?
以下代码均以C++伪代码的形式产出,基于信号量以及PV操作。

方案一:

#define N 5           //哲学家人数
semaphore fork[5];	  //信号量初值,且为1

void philos(int i)
{
	while(1)
	{
		think();              //哲学家思考
		P(fork[i]);           //拿左边的叉子
		P(fork[i + 1] % N);   //拿右边的叉子
		eat();                //进餐
		V(fork[i]);           //放下左边的叉子
		V(fork[i + 1] % N);   //放下右边的叉子
	}
}

上面的操作看似可以实现,但存在一种极端情况,假设5为哲学家都同时拿起左边的叉子,那么此时会发生死锁!,也就是说每一位哲学家都会阻塞在P(fork[i + 1] % N);这条语句上,很明显发生死锁!

方案二:

既然方案一会存在死锁的可能,那么我们引入互斥量来保证不发生死锁!

#define N 5           //哲学家人数
semaphore fork[5];	  //信号量初值,且为1
semaphore mutex;

void philos(int i)
{
	while(1)
	{
		think();              //哲学家思考
		P(mutex);             //进入临界区
		P(fork[i]);           //拿左边的叉子
		P(fork[i + 1] % N);   //拿右边的叉子
		eat();                //进餐
		V(fork[i]);           //放下左边的叉子
		V(fork[i + 1] % N);   //放下右边的叉子
		V(mutex);             //推出临界区
	}
}

上述程序中互斥量的作用在于,只要有一个哲学家进入了临界区,也就是准备拿叉子时,其他哲学家是互斥不可访问临界区的,这又当这个哲学家吃完了退出临界区后,其他哲学家才可以拿叉子进餐。
但是,该方案虽然可以让哲学家们按顺序吃饭,但是每次进餐只允许一位哲学家,从效率上讲不是最好的解决方案!

方案三:

基于方案二使用了互斥量使得效率低下,方案一问题在于所有哲学家同时拿起一边的叉子出现死锁的问题,基于这两点做改进,让偶数编号的哲学家先拿左边的再拿右边的,让奇数编号的哲学家先拿右边的叉子,再拿左边的叉子!

#define N 5           //哲学家人数
semaphore fork[5];	  //信号量初值,且为1

void philos(int i)
{
	while(1)
	{
		think();                  //哲学家思考
		if(i % 2 == 0)
		{
			P(fork[i]);           //拿左边的叉子
			P(fork[i + 1] % N);   //拿右边的叉子
		}
		else
		{
			P(fork[i + 1] % N);   //拿右边的叉子
			P(fork[i]);           //拿左边的叉子
		}
		eat();                    //进餐
		V(fork[i]);               //放下左边的叉子
		V(fork[i + 1] % N);       //放下右边的叉子
	}
}

上面的程序,在P操作时,根据哲学家的编号不同,拿起左右两边叉子的顺序不同。另外,V的操作上是不需要分支的,因为V操作是不会阻塞的。

  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值