OS实验-哲学家就餐问题(含代码实现)
问题描述
五个哲学家共有五只筷子,平时,一个哲学家进行思考,饥饿时便试图取其左右最靠近它的筷子,只有他拿到两只筷子时才能进餐。进餐毕,放下筷子继续思考。吃饭程序是:先取左边筷子,再取右边筷子,再吃饭,再放筷子。
实现方式
——最多只允许四个“哲学家”同时进入临界区。
因为如果最多四个哲学家进入临界区,则一定有人可以吃饭,以此来解决死锁的问题。
在代码实现时,以循环队列的方式为每个筷子(需要互斥访问)设一把锁(信号量,初值为1)— Chopsticks[5] = {1,1,1,1,1},若拿起筷子则置0,放下则置1,使用wait与signal函数来对数字量进行设置。同时设置一资源型信号量Room,Room最大允许值为4,最小为0。
主函数中使用folk()函数来创建进程,模拟五个哲学家。
代码实现
/**
************************************************************
************************************************************
* 作者: 曾彬芮
*
* 日期: 2021-03-30
*
* 版本: V1.0
*
* 说明: 哲学家就餐问题的一种解法
************************************************************
************************************************************
**/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define MAX_BUFFER_SIZE 5
#define MAX_PHILOSOPHER 4
int Chopstick[MAX_BUFFER_SIZE] = {1,1,1,1,1}; //代表五个筷子
int Room = 0; //表示有多少个哲学家在吃饭
//函数的声明
void Wait(int number);
void Signal(int number);
void Think(int i, int my_id);
void Eat(int i, int my_id);
void Philosopher(int i, int my_id);
//函数的实现,其中wait和signal函数是用数字来模拟PV操作
void Wait(int number)
{
number --;
}
void Signal(int number)
{
number ++;
}
void Think(int i, int my_id)
{
printf("I am philosopher %d and my id is: %d I'm thinking\n",i,my_id);
}
void Eat(int i, int my_id)
{
printf("I am philosopher %d and my id is: %d I'm eating\n",i,my_id);
}
void Philosopher(int i, int my_id){
if(Room==MAX_PHILOSOPHER || Chopstick[i]==0 || Chopstick[(i+1)%5] == 0){
wait(2);
} //若任何一种情况发生则等待
Think(i,my_id);
Signal(Room); //Room+1,则进入临界区的哲学家人数加一
Wait(Chopstick[i]); //拿起左筷子
Wait(Chopstick[(i+1)%5]); //拿起右筷子
Eat(i,my_id);
Signal(Chopstick[i]); //放下左筷子
Signal(Chopstick[(i+1)%5]); //放下右筷子
printf("I am philosopher %d and my id is: %d I finished eating\n",i,my_id);
Wait(Room); //哲学家离开临界区
}
int main()
{
int i, philosopher;
for(i=1; i<(MAX_PHILOSOPHER+1); ++i)
{
philosopher = fork();
if(philosopher==-1){
perror("fork failed");
exit(1);
}
if(philosopher == 0){
break; //防止子进程再次创建进程
}
}
sleep(1); //等待所有进程创建完毕
Philosopher(i, getpid());
return 0;
}
代码完成后在Linux终端使用命令 gcc -o ### ###.c 编译,再输入 ./### 运行即可(###表示文件名)。
以上代码均为自己编写,并已在Linux虚拟机下成功编译运行,若仍有问题还劳烦各位读者朋友指正!
2021.3.31