(2)什么是哲学家就餐问题?利用信号量写出解决哲学家就餐问题的同步程序。
时间: 2023-10-08 20:07:43 浏览: 48
哲学家就餐问题是一个经典的并发问题,描述了五个哲学家围坐在桌子前,每人面前有一碗饭和一只筷子,五只筷子放在桌子中央。他们只能拿起自己左右两边的筷子来进餐,而每人吃饭时间较长,需要两只筷子。
这个问题的关键在于如何避免死锁,即每个哲学家都拿起自己左边的筷子,导致无法再拿到右边的筷子。
以下是一个使用信号量解决哲学家就餐问题的同步程序:
```c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#define N 5 // 哲学家数量
#define LEFT (i+N-1)%N // 左邻居
#define RIGHT (i+1)%N // 右邻居
#define THINKING 0 // 思考
#define HUNGRY 1 // 饥饿
#define EATING 2 // 就餐
int state[N]; // 哲学家状态
pthread_mutex_t mutex; // 互斥锁
sem_t sem[N]; // 信号量
void *philosopher(void *arg) {
int i = *(int *)arg;
while (1) {
printf("Philosopher %d is thinking...\n", i);
sleep(rand() % 5);
printf("Philosopher %d is hungry...\n", i);
state[i] = HUNGRY;
test(i); // 尝试取得两只筷子
sem_wait(&sem[i]); // 等待信号量
printf("Philosopher %d is eating...\n", i);
sleep(rand() % 5);
printf("Philosopher %d has finished eating...\n", i);
sem_post(&sem[LEFT]); // 放回左侧筷子
sem_post(&sem[RIGHT]); // 放回右侧筷子
}
}
void test(int i) {
if (state[i] == HUNGRY && state[LEFT] != EATING && state[RIGHT] != EATING) {
state[i] = EATING;
sem_post(&sem[i]); // 释放信号量
}
}
int main() {
pthread_t tid[N];
int i, id[N];
for (i = 0; i < N; i++) {
state[i] = THINKING;
sem_init(&sem[i], 0, 0);
id[i] = i;
}
pthread_mutex_init(&mutex, NULL);
for (i = 0; i < N; i++) {
pthread_create(&tid[i], NULL, philosopher, &id[i]);
}
for (i = 0; i < N; i++) {
pthread_join(tid[i], NULL);
}
return 0;
}
```
在这个程序中,每个哲学家(线程)都有一个状态,包括 THINKING(思考)、HUNGRY(饥饿)和 EATING(就餐)。每个筷子(信号量)初始值为 0,表示不可用。当一个哲学家饥饿时,它会试图取得左右两只筷子,如果两只筷子都可用,那么它就开始就餐;否则,它会等待信号量,直到两只筷子都可用。就餐结束后,哲学家会放回两只筷子,这样其他哲学家就可以使用它们了。