哲学家用餐问题程序解决

 代码仓库:JJLi0427/operationsystem (github.com)

1.问题描述:

一些哲学家围坐在圆桌旁,他们的两边都只有一根筷子。一般情况下他们都在思考着自己的问题,如果他们饿了,他们就需要吃饭,但是吃饭需要用一对筷子,即左右的两个筷子都得拿到手上才能开饭。

2.解决思路:

这是个很经典的同步问题,在这里可以把每个筷子和编号,若哲学家是i左边的筷子为i,右边的筷子是i+1,每个筷子都是一个独立的信号量置为1。若只按照这些条件设计程序运行,就会发现程序会很容易进入死锁状态,即每个哲学家都拿了一个筷子,这样谁都吃不上饭。为了解决死锁问题,有很多种方式。这里我采用了限制用餐人数来解决问题。把用餐人数的信号量设置为哲学家人数减1,就不会发生死锁了。

3.程序实现:

c++实现如下,编译时需加上 -lpthread

#include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
using namespace std;

const int num = 5; //设置哲学家的人数
sem_t chopstick[num], eatman; //创建筷子信号量和就餐人数上限信号量
typedef struct ThreadData {
    int id;
    int think;
    int eat;
} tdata; //线程的数据结构

void* philosopher(void* p) {
    int id = ((tdata*)p)->id;
    int think = ((tdata*)p)->think;
    int eat = ((tdata*)p)->eat;

    sleep(think);
    printf("philosopher %d: is thinking\n", id);

    sem_wait(&eatman);
    sem_wait(&chopstick[id]); //拿起左边的筷子
    sem_wait(&chopstick[(id + 1) % num]); //拿起右边的筷子
    sem_post(&eatman);

    printf("philosopher %d: start eating\n", id);
    sleep(eat); 
    printf("philosopher %d: end eating\n", id);

    sem_post(&chopstick[id]); //放下左边的筷子
    sem_post(&chopstick[(id + 1) % 5]); //放下右边的筷子
    pthread_exit(0);
    return NULL;
}

int main() {
    pthread_t tid[num]; //线程号初始化
    pthread_attr_t attr;
    pthread_attr_init(&attr); //线程属性初始化
    sem_init(&eatman, 0, num-1);
    for(int i = 0; i < num; i++) {
        sem_init(&chopstick[i], 0, 1); //初始化所有的筷子,信号量都为1
    }

    int thinklist[num] = {2, 6, 5, 3, 1};
    int eatlist[num] = {8, 3, 4, 5, 2}; //设置哲学家的思考时间和吃饭时间
    for(int id = 0; id < num; id++) {
        tdata* d = new tdata;
        d->id = id;
        d->think = thinklist[id];
        d->eat = eatlist[id];
        printf("create philosopher %d\n", id);
        pthread_create(&tid[id], &attr, philosopher, d); //创建哲学家线程
    }
    for(int i = 0; i < num; i++) {
        pthread_join(tid[i], NULL); //等待所有哲学家线程结束
    }

    sem_destroy(&eatman); //销毁信号量
    for(int i = 0; i < num; i++) {
        sem_destroy(&chopstick[i]); 
    }
    return 0;
}

4.运行结果:

create philosopher 0
create philosopher 1
create philosopher 2
create philosopher 3
create philosopher 4
philosopher 4: is thinking
philosopher 4: start eating
philosopher 0: is thinking
philosopher 0: start eating
philosopher 3: is thinking
philosopher 3: start eating
philosopher 4: end eating
philosopher 2: is thinking
philosopher 2: start eating
philosopher 1: is thinking
philosopher 1: start eating
philosopher 3: end eating
philosopher 2: end eating
philosopher 1: end eating
philosopher 0: end eating

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哆啦叮当

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值