哲学家进餐问题c代码实现
时间: 2024-05-01 18:16:49 浏览: 93
以下是一个基于信号量的解法,使用了pthread库和semaphore.h头文件:
```c
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define N 5 // 哲学家数目
#define LEFT (i + N - 1) % N // 左邻居编号
#define RIGHT (i + 1) % N // 右邻居编号
int state[N]; // 哲学家的状态
const char* state_name[] = {"THINKING", "HUNGRY", "EATING"}; // 状态名称
pthread_mutex_t mutex; // 互斥锁
sem_t s[N]; // 信号量
void test(int i) {
if (state[i] == 1 && state[LEFT] != 2 && state[RIGHT] != 2) {
state[i] = 2;
printf("Philosopher %d is eating.\n", i);
sem_post(&s[i]); // 释放信号量
}
}
void take_forks(int i) {
pthread_mutex_lock(&mutex); // 加锁
state[i] = 1;
printf("Philosopher %d is hungry.\n", i);
test(i);
pthread_mutex_unlock(&mutex); // 解锁
sem_wait(&s[i]); // 获取信号量
sleep(1); // 吃饭
}
void put_forks(int i) {
pthread_mutex_lock(&mutex); // 加锁
state[i] = 0;
printf("Philosopher %d puts down forks and starts thinking.\n", i);
test(LEFT);
test(RIGHT);
pthread_mutex_unlock(&mutex); // 解锁
}
void* philosopher(void* arg) {
int i = *(int*)arg;
while (1) {
take_forks(i);
put_forks(i);
}
}
int main() {
pthread_t tid[N];
int i;
for (i = 0; i < N; i++) {
state[i] = 0;
sem_init(&s[i], 0, 0); // 初始化信号量
}
pthread_mutex_init(&mutex, NULL); // 初始化互斥锁
int id[N];
for (i = 0; i < N; i++) {
id[i] = i;
pthread_create(&tid[i], NULL, philosopher, &id[i]); // 创建线程
}
for (i = 0; i < N; i++) {
pthread_join(tid[i], NULL); // 等待线程结束
}
pthread_mutex_destroy(&mutex); // 销毁互斥锁
for (i = 0; i < N; i++) {
sem_destroy(&s[i]); // 销毁信号量
}
return 0;
}
```
在该程序中,每个哲学家都是一个线程,其中`state[i]`表示哲学家`i`的状态(0表示思考,1表示饥饿,2表示就餐)。`pthread_mutex_t mutex`是一个互斥锁,用于保证同时只有一个哲学家进入临界区(即执行`test()`和修改状态)。`sem_t s[N]`是一个信号量数组,其中`s[i]`表示哲学家`i`的信号量,用于解决死锁问题。
在`take_forks()`中,首先将哲学家的状态置为1(饥饿),然后调用`test()`函数,检查周围的哲学家是否都没有在用餐。如果是,则将当前哲学家的状态置为2(就餐),并释放`s[i]`信号量。否则,当前线程将会阻塞,并等待周围的哲学家用餐完毕后释放信号量。使用`sleep(1)`模拟哲学家进餐的时间。
在`put_forks()`中,先将哲学家的状态置为0(思考),然后调用`test()`函数,检查周围的哲学家是否可以开始进餐。
在`test()`函数中,如果当前哲学家的状态为1(饥饿),且它的左右邻居都没有在用餐,那么当前哲学家就可以开始进餐了。这里需要注意,为了避免死锁,每个哲学家都是先尝试拿起右边的叉子,再尝试拿起左边的叉子。
最后,需要在主函数中创建并等待所有哲学家线程的结束。程序使用了`sem_init()`和`sem_destroy()`函数初始化和销毁信号量,使用了`pthread_mutex_init()`和`pthread_mutex_destroy()`函数初始化和销毁互斥锁。
阅读全文