目录
实验原理:
实验目的:
实验数据及结果分析:
-
实验原理:
哲学家进餐问题可以通过限制同时进餐人数为4解决,为此需要设置一个值为4的互斥信号量sem_eaters,并且每根筷子只能同时由一个人使用,需要设置一个值为1的互斥信号量数组sem_chopstics。C语言中提供了实现信号量和线程创建等方法的库,可以使用C语言在ubuntu操作系统上实现哲学家进餐问题的解决。
-
实验目的:
- 掌握哲学家就餐问题,掌握预防死锁的实现方法;
- 了解Linux系统下进程和线程的实现;
- 掌握通过互斥量、POSIX信号量、XSI信号量集实现多线程/多进程同步控制的方法
- 实验内容:
熟悉Ubuntu系统环境和命令;熟悉Ubuntu系统下的多线程/多进程编程;在Ubuntu系统下编程实现哲学家就餐问题。实现教材2.5.2节中所描述的哲学家就餐问题。要求显示出每个哲学家的工作状态,如吃饭,思考。连续运行30次以上都未出现死锁现象。
- 实验器材(设备、元器件):
PC计算机,操作系统:Ubuntu
- 实验步骤:
- 了解C语言实现线程互斥中的信号量、线程等使用方式
本实验主要用到了POSIX信号量,来自semaphore.h和来自pthread.h的线程创建等方法。
如sem_init()初始化信号量,sem_post()对信号量进行V操作,phtread_create()创建线程等函数,实现哲学家进餐问题。
- 考虑哲学家进餐问题的实现
本次实验中采用约束同时进餐人数的方式避免死锁发生,当同时进餐人数最多为4人的时候,不会发生死锁(还有同时请求两根筷子等解决方案,这里只说明其中一种)。可以通过一个初始值为4的信号量sem_eaters控制,以达到目的。
- 编写代码
图1
- 使用gcc编译.c文件
图2
- 执行编译后的文件
图3
- 运行结果
图4
-
实验数据及结果分析:
实验数据 | 类型 | 初始化 |
sem_eaters信号量 | sem_t | sem_init 值为4 |
sem_chopstics信号量数组 | sem_t | sem_init 值为1 |
PID数组 | Int | {0,1,2,3,4} |
pthreads数组 | pthread_t | 使用pthread_create初始化 |
循环次数 | Int | 70 |
通过70次循环哲学家问题,没有发现报错,即没有出现死锁,均正常执行。
实验代码如下:
- #include <stdio.h>
- #include <stdlib.h>
- #include <pthread.h>
- #include <semaphore.h>
- sem_t sem_eaters;//记录哲学家信号量
- sem_t sem_chopstics[5];//记录筷子信号量
- int PID[5] = {0,1,2,3,4};//记录进程ID
- int num = 0;//记录当前已进餐人数
- //初始化
- void init(){
- int i = 0, j ,k;
- for (;i < 5;i++)
- {
- j = sem_init(&sem_chopstics[i],0,1);//初始化每一根筷子为值为1的信号量
- if (j == -1) {
- perror("初始化sem_chopstics信号量失败\n");
- exit(1);
- }
- }
- k = sem_init(&sem_eaters,0,4);//初始化哲学家信号量,即控制同时进餐的人数
- if (k == -1)
- {
- perror("初始化sem_eaters信号量失败\n");
- exit(1);
- }
- }
- void * method(int* pid){
- int p_num = (*pid) % 5;//当前进餐的哲学家编号
- pirntf("当前第%d号哲学家思考中\n",&p_num);
- sem_wait(&sem_eaters);
- printf("拿起第%d根筷子\n",&p_num);
- sem_wait(&sem_chopstics[p_num]);
- printf("拿起第%d根筷子\n",&((p_num+1) % 5));
- sem_wait(&sem_chopstics[(p_num+1)%5]);
- pirntf("当前第%d号哲学家正在进餐~~\n",&p_num);
- num++;//吃完了
- pirntf("当前第%d号哲学家已经吃完了\n",&p_num);
- //释放资源
- sem_post(&sem_chopstics[(p_num)%5]);
- sem_post(&sem_chopstics[(p_num+1)%5]);
- sem_post(&sem_eaters);
- }
- int main()
- {
- for (int i = 1;i <= 50 ;i++ )
- {
- pthread_t pthreads[5];
- printf("这是第%d次哲学家进餐问题\n",&i);
- init();//初始化信号量
- for (int j = 0;j < 5 ;j++ )
- {
- printf("创建第%d号线程\n",j);
- int k = 0;
- k = pthread_create(&pthreads[j],NULL,method,&PID[j]);//传入进程执行的方法method 要求是void *类型,并且传入函数需要的参数
- if (k == -1) {
- perror("线程创建失败\n");
- exit(1);
- }
- }
- for (int l = 0; l < 5;l++ )
- {
- pthread.join(pthreads[l],NULL);
- }
- //结束:销毁所有信号量
- sem_destroy(&sem_eaters);
- for (int p = 0;p < 5;p++) {
- sem_destroy(&sem_chopstics[p]);
- }
- num = 0;
- }
- return 0;
- }