哲学家就餐问题

原文链接: https://blog.csdn.net/Yun_Ge/article/details/89177918

有五个哲学家,每个哲学家之间有一只筷子,必须同时获得两只筷子才能进餐。平时一个哲学家进行思考,饥饿时便试图取用其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐。进餐完毕,放下筷子又继续思考。
哲学家就餐问题_第1张图片
在就餐时会引发两个问题:
1.死锁 :每个哲学家持有一只筷子,等待相邻哲学家释放另一只筷子而形成循环等待的状态。
2.饥饿:所有哲学家同时持有一只筷子,因无法得到两只而同时释放,发现条件满足又同时拿起,如此循环,所有哲学家处于饥饿状态。

解决办法一:

规定奇数号哲学家先拿左筷子再拿右筷子,而偶数号哲学家相反。
将是 2,3 号哲学家竞争 2号筷子,4,5 号哲学家竞争 5 号筷子。1 号哲学家不需要竞争。竞争过程中总有一方获得筷子,最后至少一个哲学家能获得两支筷子而进餐。

semaphore status[5] = { 1,1,1,1,1 };
//哲学家线程
void philosopher(int id)
{
	while (true)
	{
		think();
		if (id % 2)
		{
			wait(status[id]);//左边
			wait(status[(id + 1) % 5]);//右边
			eat();
			signal(status[(id + 1) % 5]);
			signal(status[id]);
		}
		else
		{
			wait(status[(id + 1) % 5]);//右边
			wait(status[id]);//左边
			eat();
			signal(status[id]);
			signal(status[(id + 1) % 5]);
		}
		think();
	}
}

解决办法二:

要么同时拿起要么不拿,吧取两双筷子封装成原子操作。使用互斥量或者临界区实现。

mutex mt;
semaphore status[5] = { 1,1,1,1,1 };
//哲学家线程
void philosopher(int id)
{
	while (true)
	{
		think();
		unique_lock<mutex> lock(mt);//把同时拿两只筷子变成原子操作。
		wait(status[id]);
		wait(status[(id + 1) % 5]);
		lock.unlock();

		eat();
		signal(status[(id + 1) % 5]);
		signal(status[id]);
		think();
	}
}

解决方法三:
设置一个初值为 4 的信号量 r,只允许 4 个哲学家同时去拿左筷子,这样就能保证至少有一个哲学家可以就餐,不会出现饿死和死锁的现象。

semaphore sm(4);
semaphore status[5] = { 1,1,1,1,1 };
//哲学家线程
void philosopher(int id)
{
	while (true)
	{
		think();
		wait(sm);
		wait(status[id]);
		wait(status[(id + 1) % 5]);
		eat();
		signal(status[(id + 1) % 5]);
		signal(status[id]);
		signal(sm);
		think();
	}
}

另附c++下信号量简单实现。因为此问题中五只筷子属于五种资源而不是同一资源的5个,所以用5个信号量而不是用一个值为5的信号量。

struct semaphore
{
	semaphore() : cnt(0) {}
	semaphore(int i) :cnt(i) {}
	condition_variable cv;
	mutex mt;
	int cnt;
};

void wait(semaphore& sm)
{
	unique_lock<mutex> lock(sm.mt);
	sm.cv.wait(lock, [&]()->bool { return sm.cnt > 0; });
	sm.cnt--;
}

void signal(semaphore& sm)
{
	unique_lock<mutex> lock(sm.mt);
	sm.cnt++;
	sm.cv.notify_one();
}

参考:
https://blog.csdn.net/Yun_Ge/article/details/89177918

你可能感兴趣的:(C++小记)