目录
1、问题描述:
2、问题分析:
3、 解决方案:
4、源代码:
5、结果截图:
问题描述:
针对5位哲学家就餐问题,采用奇数号哲学家先拿起左边的筷子,再去拿右边的筷子;而偶数号哲学家则用相反的方法,进行解决。假设每位哲学家思考5秒,进餐3秒,给出100秒内每位哲学家进餐的总次数。(25分)
问题分析:
为了解决五个哲学家争用的资源的问题,我们可以采用以下几种解决方法:
1、至多只允许有四位哲学家同时去拿左边的筷子,最终能保证至少有一位哲学家能够进餐,并在用餐完毕后能释放他占用的筷子,从而使别的哲学家能够进餐;
2、仅当哲学家的左、右两支筷子可用时,才允许他拿起筷子;
3、规定奇数号哲学家先拿他左边的筷子,然后再去拿右边的筷子;而偶数号哲学家则相反。
解决方案:
根据本题要求,规定奇数号哲学家先拿他左边的筷子,然后再去拿右边的筷子;而偶数号哲学家则相反。
源代码:
源程序:
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
// 线程个数,即哲学家个数
#define PhilosopherNum 5
sem_t* sem_fork; //定义一组餐叉的信号量
int count[PhilosopherNum]; // 记录每个哲学家的用餐次数
pthread_t* thread_handles;
void handler(int s) {
pthread_exit(NULL);
}
// 模拟哲学家就餐解决方案
void* method(void* rank) {
// 用long而不是int 消除void* 转换时的warnning
long my_rank = (long)rank;
// 注册信号处理函数
struct sigaction sa;
sa.sa_handler = handler;
sigfillset(&sa.sa_mask);
sigaction(SIGALRM, &sa, NULL);
//表示哲学家左右的叉子
long my_left_fork, my_right_fork;
//奇数先左叉后右叉,偶数先右叉后左叉
if (my_rank % 2 == 1) {
my_left_fork = (my_rank + 1) % PhilosopherNum;
my_right_fork = my_rank;
} else {
my_left_fork = my_rank;
my_right_fork = (my_rank + 1) % PhilosopherNum;
}
while (1) {
printf("Philosopher %ld is thinking\n", my_rank);
// thinking
sleep(5);
printf("Philosopher %ld is trying\n", my_rank);
sem_wait(&sem_fork[my_left_fork]);
sem_wait(&sem_fork[my_right_fork]);
printf("Philosopher %ld is eating\n", my_rank);
count[my_rank]++;
// eating
sleep(3);
sem_post(&sem_fork[my_left_fork]);
sem_post(&sem_fork[my_right_fork]);
}
}
int main(int argc, char* argv[]) {
thread_handles = malloc(PhilosopherNum * sizeof(pthread_t));
sem_fork = malloc(PhilosopherNum * sizeof(sem_t));
//初始化所有叉子信号量
for (size_t i = 0; i < PhilosopherNum; i++) {
sem_init(&sem_fork[i], 0, 1);
}
//创建线程
for (size_t thread = 0; thread < PhilosopherNum; thread++) {
//根据参数进入相应的处理函数
pthread_create(&thread_handles[thread], NULL, method, (void*)thread);
// 一定不能将线程设为join
// pthread_join(thread_handles[thread], NULL);
}
sleep(100);
//停止线程
for (size_t thread = 0; thread < PhilosopherNum; thread++) {
pthread_kill(thread_handles[thread], SIGALRM);
}
// 打印用餐次数
for (int i = 0; i < PhilosopherNum; i++) {
printf("The number of philosopher %d meals is :%d\n", i, count[i]);
}
//销毁餐叉信号量
for (size_t i = 0; i < PhilosopherNum; i++) {
sem_destroy(&sem_fork[i]);
}
//释放空间
free(thread_handles);
free(sem_fork);
return 0;
}
运行方法:
gcc work1.c -o work1 -lpthread
./work1
结果截图:
注:由于题目要求100秒内,所以使用得sleep(5)sleep(3)等,使得执行结果输出很多页,在此不再粘贴部分截图。
运行结果:
root@hjh-virtual-machine:/# ./work1
Philosopher 3 is thinking
Philosopher 0 is thinking
Philosopher 4 is thinking
Philosopher 2 is thinking
Philosopher 1 is thinking
Philosopher 3 is trying
Philosopher 0 is trying
Philosopher 0 is eating
Philosopher 3 is eating
....
......
.......
.........
The number of philosopher 0 meals is :12
The number of philosopher 1 meals is :12
The number of philosopher 2 meals is :12
The number of philosopher 3 meals is :12
The number of philosopher 4 meals is :12
* usleep的单位是毫秒,可以用毫秒做测试
* 题目要求的单位是秒,可以直接替换为sleep(单位为秒)可以设置为100秒观察效果