void philosopher(int i); // the array and the variable below storage their sem_id int chopsticks[5]; int main(int argc, char* args[]) { for (int i = 0; i < 5; ++i) chopsticks[i] = CreateSem(1); int fpid = 1; int amount = 5; while (fpid != 0 && --amount) fpid = fork(); philosopher(amount); return 0; } void philosopher(int i) { printf("my i = %d\n", i); while (true) { think(i); // for each philosopher, the i-th chopstick is at his left, // and the (i + 1) % 5 th chopstick is at his right; // odd get left first, and even get right first if (i % 2 == 1) { Psem(chopsticks[i]); printf("philosopher %d get left\n", i); Psem(chopsticks[(i + 1) % 5]); printf("philosopher %d get right\n", i); eat(i); Vsem(chopsticks[i]); printf("philosopher %d put down left\n", i); Vsem(chopsticks[(i + 1) % 5]); printf("philosopher %d put down right\n", i); } else { Psem(chopsticks[(i + 1) % 5]); printf("philosopher %d get right\n", i); Psem(chopsticks[i]); printf("philosopher %d get left\n", i); eat(i); Vsem(chopsticks[(i + 1) % 5]); printf("philosopher %d put down right\n", i); Vsem(chopsticks[i]); printf("philosopher %d put down left\n", i); } } }
时间: 2024-01-05 19:04:03 浏览: 89
这段代码实现了五个哲学家就餐问题的解决方案。整个程序分为两个部分:主函数和哲学家函数。
在主函数中,首先创建了五个二元信号量,用于表示五个餐叉是否被占用。然后通过循环创建五个子进程,每个子进程调用哲学家函数进行就餐。
在哲学家函数中,首先输出当前哲学家的编号,然后进入一个无限循环。在循环中,哲学家会先思考一段时间(调用 think 函数),然后尝试获取左右两个餐叉。
对于奇数号哲学家,先获取左边的餐叉,再获取右边的餐叉;对于偶数号哲学家,则相反。如果无法同时获取到两个餐叉,哲学家就会一直等待,直到获取到餐叉。
一旦成功获取到两个餐叉,哲学家就会进入就餐状态(调用 eat 函数)。就餐完毕后,哲学家会先放下左边的餐叉,再放下右边的餐叉,然后继续思考。
在放下餐叉时,需要调用 Vsem 函数释放相应的信号量,表示该餐叉空闲可用。
相关问题
#include <iostream> #include <thread> #include <mutex> #include <condition_variable> using namespace std; const int N = 5; // 哲学家数量 mutex forks[N]; // 叉子互斥锁 condition_variable cv[N]; // 条件变量,用于线程同步 void philosopher(int i) { while (true) { // 模拟思考 cout << "Philosopher " << i << " is hungry." << endl; // 拿起左手的叉子 forks[i].lock(); cout << "Philosopher " << i << " picks up left fork." << endl; // 尝试拿起右手的叉子 unique_lock<mutex> lock(forks[(i + 1) % N], defer_lock); while (!lock.try_lock()) { cv[i].wait(lock); } cout << "Philosopher " << i << " picks up right fork." << endl; // 进餐 cout << "Philosopher " << i << " starts eating." << endl; this_thread::sleep_for(chrono::milliseconds(rand() % 1000)); cout << "Philosopher " << i << " finishes eating." << endl; // 放下右手的叉子 lock.unlock(); cv[(i + 1) % N].notify_one(); cout << "Philosopher " << i << " puts down right fork." << endl; // 放下左手的叉子 forks[i].unlock(); cout << "Philosopher " << i << " puts down left fork." << endl; } } int main() { thread philosophers[N]; for (int i = 0; i < N; i++) { philosophers[i] = thread(philosopher, i); } for (int i = 0; i < N; i++) { philosophers[i].join(); } return 0; }分析案例
这是一个经典的哲学家就餐问题,使用了互斥锁和条件变量来实现线程同步。
在哲学家就餐问题中,有5个哲学家围坐在一张圆桌前,每个哲学家面前都有一只叉子。哲学家只有在同时拿到左右两只叉子时才能进餐,进餐完毕后需要放下叉子。
在代码实现中,每个哲学家对应一个线程,线程函数philosopher(i)模拟了哲学家的行为。当哲学家饥饿时,首先尝试拿起左手的叉子,如果成功则继续尝试拿起右手的叉子,如果失败则等待。当哲学家成功拿起左右两只叉子时,进餐一段时间后放下叉子,释放右手的叉子,并通知右边的哲学家可以拿起叉子了。
通过互斥锁保证了同一时刻只能有一个哲学家拿起同一只叉子,通过条件变量实现线程间的等待和通知,以避免死锁和忙等待的问题。
该实现方式在一定程度上解决了哲学家就餐问题,但仍存在一些问题,例如可能会出现饥饿死锁等问题。在实际应用中,需要根据具体情况进行进一步的优化和改进。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <semaphore.h> #include <time.h> #define N 5 pthread_mutex_t chopstick[N];//筷子信号量 //哲学家线程函数 void* philosopher(void* arg){ int *i; i = (int *)arg;//哲学家序号 for(;;){ //思考 printf("%d 号哲学家在思考......\n",*i); sleep(rand()%3);//休眠随机时间,不超过3秒 //尝试取回左右两边的筷子 if(pthread_mutex_trylock(&chopstick[*i]) == 0 && pthread_mutex_trylock(&chopstick[(*i+1)%N]) == 0)//尝试同时拿到两个筷子 { //成功拿到两个筷子 printf("%d号哲学家在进餐......\n",*i); sleep(rand()%3);//休眠随机时间,不超过3秒 //放回筷子 pthread_mutex_unlock(&chopstick[*i]); pthread_mutex_unlock(&chopstick[(*i+1)%N]); } else { //释放已拿到的筷子,等待随机时间后重试 pthread_mutex_unlock(&chopstick[*i]); pthread_mutex_unlock(&chopstick[(*i+1)%N]); sleep(rand()%2); } } } int main(){ pthread_t id[N]; int i; for(i=0;i<N;i++) pthread_mutex_init(&chopstick[i],NULL); for(i=0;i<N;i++) { int *p; p=malloc(sizeof(int)); *p=i; pthread_create(&id[i],NULL,philosopher,(void*)p); } for(i=0;i<N;i++) pthread_join(id[i],NULL); }给代码加注释
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <time.h>
#define N 5 //哲学家数量
pthread_mutex_t chopstick[N]; //筷子信号量
//哲学家线程函数
void* philosopher(void* arg){
int *i;
i = (int *)arg; //哲学家序号
for(;;){
//思考
printf("%d 号哲学家在思考......\n",*i);
sleep(rand()%3); //休眠随机时间,不超过3秒
//尝试取回左右两边的筷子
if(pthread_mutex_trylock(&chopstick[*i]) == 0 && pthread_mutex_trylock(&chopstick[(*i+1)%N]) == 0) //尝试同时拿到两个筷子
{
//成功拿到两个筷子
printf("%d号哲学家在进餐......\n",*i);
sleep(rand()%3); //休眠随机时间,不超过3秒
//放回筷子
pthread_mutex_unlock(&chopstick[*i]);
pthread_mutex_unlock(&chopstick[(*i+1)%N]);
}
else
{
//释放已拿到的筷子,等待随机时间后重试
pthread_mutex_unlock(&chopstick[*i]);
pthread_mutex_unlock(&chopstick[(*i+1)%N]);
sleep(rand()%2);
}
}
}
int main(){
pthread_t id[N];
int i;
//初始化筷子信号量
for(i=0;i<N;i++)
pthread_mutex_init(&chopstick[i],NULL);
//创建哲学家线程
for(i=0;i<N;i++)
{
int *p;
p=malloc(sizeof(int));
*p=i;
pthread_create(&id[i],NULL,philosopher,(void*)p);
}
//等待哲学家线程结束
for(i=0;i<N;i++)
pthread_join(id[i],NULL);
}
```
代码中实现了哲学家问题的解决方案,通过线程模拟哲学家的行为,使用互斥锁来解决筷子竞争的问题。其中,`pthread_mutex_init`用于初始化互斥锁,`pthread_create`用于创建线程,`pthread_join`用于等待线程结束。对于每一个哲学家线程,其会进入一个无限循环,先进行思考,然后尝试取回左右两边的筷子,如果成功则进餐,否则释放已拿到的筷子并等待随机时间后重试。
阅读全文