实验目的
哲学家就餐问题的实现:
- 实现哲学家就餐问题,要求不能出现死锁;
- 通过本实验熟悉 Linux 系统的基本环境,了解 Linux 下进程和线程的实现。
实验原理
该问题是描述有五个哲学家共用一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五只筷子,他们的生活方式是交替地进行思考和进餐。平时,一个哲学家进行思考,饥饿时便试图取用其左右最靠近他的筷子,只有在他拿到两只筷子时才能进餐。进餐完毕,放下筷子继续思考。
- 关系分析:5 名哲学家与左右邻居对其中间筷子的访问是互斥关系。
- 为了实现哲学家对筷子的获取关系,显然这里有 5 个进程(线程)。实验的关键是如何让一个哲学家拿到左右两个筷子而不造成死锁或者饥饿现象。
- 用信号量或者互斥量实现对 5 个筷子的互斥访问。对哲学家按顺序从 0~4 编号,哲学家 i 左边的筷子的编号为 i,哲学家右边的筷子的编号为(i+1)%5。
实验内容
在 Linux 系统下实现教材 2.5.2 节中所描述的哲学家就餐问题。要求显示出每个哲学家的工作状态,如吃饭,思考。连续运行 30 次以上都未出现死锁现象。
(1)熟悉 Ubuntu 系统环境和命令;
(2)熟悉 Ubuntu 系统下的多线程编程;
(3)在 Ubuntu 系统下编程实现哲学家就餐问题。
实验器材
硬件环境:个人计算机
操作系统:CentOS 7
实验步骤
(1)熟悉 Ubuntu 系统下的多线程编程
- 使用 Ctrl+Alt+T 打开终端;
- 使用 gedit 或 vim 命令打开文本编辑器进行编码:gedit 文件名.c;
- 编译程序:gcc 文件名.c -o 可执行程序名(如果只输入 gcc 文件名.c,默认可执行程序名为 a.out)使用线程库时,gcc 编译需要添加-lpthread;
- 执行程序:./可执行程序名;
(2)哲学家就餐问题的实现流程图
- 主程序流程图:
- 每位哲学家流程图:
(3)哲学家就餐问题的实现代码
-
每位哲学家进行就餐-思考循环过程。
每个哲学家若想从思考状态转为就餐状态时,先取左边的筷子,在尝试取右边的筷子。如果右边的筷子已经被取走,则放下左边的筷子。
如果可以取左右两边的筷子,那么哲学家从思考状态转为就餐状态。就餐结束后,哲学家放下左右两边的筷子,并从就餐状态又转为思考状态。
-
主程序创建 5 个线程并运行线程。
实验结果
//The Dining Philosophers Problem
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t chopstick[5]; //定义互斥量数组
void* eat_think(void* arg) {
int left, right; //左右筷子的编号
int i;
for (i = 1; i < 6; i++) {
left = i-1; //0,1,2,3,4
right = i % 5; //1,2,3,4,0
}
int phi = *(int*)arg; //哲学家编号
// printf("create Philosopher %d.\n", phi);
//开始吃饭-思考循环
while (1) {
printf("Philosopher %d is thinking.\n", phi);
usleep(5); //思考中
pthread_mutex_lock(&chopstick[left]); //拿起左手的筷子
int try = pthread_mutex_trylock(&chopstick[right]); //尝试拿起右手的筷子
if (try !=0) {
pthread_mutex_unlock(&chopstick[left]); //如果右边筷子被拿走就放下左手的筷子
continue;
}
//pthread_mutex_lock(&chopstick[right]); //会发生死锁情况
printf("Philosopher %d is eating.\n", phi);
usleep(5); //吃饭中
pthread_mutex_unlock(&chopstick[left]); //放下左手的筷子
pthread_mutex_unlock(&chopstick[right]); //放下右手的筷子
}
}
int main() {
pthread_t philosopher[5]; //5个哲学家线程
int i, mark[5] = {0,1,2,3,4};
for (i = 0; i < 5; i++) //初始化
pthread_mutex_init(&chopstick[i], NULL);
for (i = 0; i < 5; i++) //创建子线程
pthread_create(&philosopher[i], NULL, eat_think, &mark[i]); // mark[i]传递参数,哲学家编号
for (i = 0; i < 5; i++) //等待线程运行结束
pthread_join(philosopher[i], NULL);
return 0;
}
操作系统基础实验: