哲学家进餐问题

哲学家进餐问题的改进解法

  • 方法一:至多只允许四位哲学家同时去拿左筷子,最终能保证至少有一位哲学家能进餐,并在用完后释放两只筷子供他人使用。
  • 方法二:仅当哲学家的左右手筷子都拿起时才允许进餐。
  • 方法三:规定奇数号哲学家先拿左筷子再拿右筷子,而偶数号哲学家相反。

方法一

至多只允许四位哲学家同时去拿左筷子,最终能保证至少有一位哲学家能进餐,并在用完后释放两只筷子供他人使用。

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

原理:至多只允许四个哲学家同时进餐,以保证至少有一个哲学家能够进餐,最终总会释放出他所使用过的两支筷子,从而可使更多的哲学家进餐。

图示

方法二

仅当哲学家的左右手筷子都拿起时才允许进餐。

解法 1:利用 AND 型信号量机制实现。

原理:多个临界资源,要么全部分配,要么一个都不分配,因此不会出现死锁的情形。

图示

解法 2:利用信号量的保护机制实现。

原理:通过互斥信号量 mutex 对 eat() 之前取左侧和右侧筷子的操作进行保护,可以防止死锁的出现。

图示

方法三

规定奇数号哲学家先拿左筷子再拿右筷子,而偶数号哲学家相反。

原理:按照下图,将是 2,3 号哲学家竞争 3 号筷子,4,5 号哲学家竞争 5 号筷子。1 号哲学家不需要竞争。最后总会有一个哲学家能获得两支筷子而进餐。

图示

图示

代码实现:

1、进程版本

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/mman.h>
#include <sys/wait.h>
//利用信号量模拟互斥锁来实现哲学家就餐问题
int main(void)
{
	int i;
	pid_t pid;

	sem_t *s;
	s = mmap(NULL, sizeof(sem_t)*5, PROT_READ|PROT_WRITE, 
			MAP_SHARED|MAP_ANON, -1, 0);
	if (s == MAP_FAILED) {
		perror("fail to mmap");
		exit(1);
	}

	for (i = 0; i < 5; i++)
		sem_init(&s[i], 0, 1);  //信号量初值制定为1,信号量,变成了互斥锁

	for (i = 0; i < 5; i++)
		if ((pid = fork()) == 0)
			break;

	if (i < 5) {				//子进程
		int l, r;
		srand(time(NULL));

		if (i == 4) 
			l = 0, r = 4;
		else
			l = i+1, r = i;
		while (1) {
			sem_wait(&s[l]);
			if (sem_trywait(&s[r]) == 0) { //左边筷子拿到后,尝试获取右边的筷子,使用测试锁定法
				printf(" %c is eating\n", 'A'+i);
				sem_post(&s[r]);
			}
			sem_post(&s[l]);
			sleep(rand() % 5);
		}
		exit(0);
	} 

	for (i = 0; i < 5; i++)
		wait(NULL);	

	for (i = 0; i < 5; i++)
		sem_destroy(&s[i]);

	munmap(s, sizeof(sem_t)*5);
	return 0;
}

2、线程版本

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
//互斥量实现
pthread_mutex_t m[5];

void *tfn(void *arg)
{
	int i, l, r;

	srand(time(NULL));
	i = (int)arg;

	if (i == 4)
		l = 0, r = i;
	else
		l = i+1; r = i;

	while (1) {
		pthread_mutex_lock(&m[l]);
		if (pthread_mutex_trylock(&m[r]) == 0) {
			printf("\t%c is eating \n", 'A'+i);
			pthread_mutex_unlock(&m[r]);
		}
		pthread_mutex_unlock(&m[l]);
		sleep(rand() % 5);
	}

	return NULL;
}

int main(void)
{
	int i;
	pthread_t tid[5];
	
	for (i = 0; i < 5; i++)
		pthread_mutex_init(&m[i], NULL);

	for (i = 0; i < 5; i++)
		pthread_create(&tid[i], NULL, tfn, (void *)i);

	for (i = 0; i < 5; i++)
		pthread_join(tid[i], NULL);

	for (i = 0; i < 5; i++)
		pthread_mutex_destroy(&m[i]);

	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Star星屹程序设计

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值