《操作系统》同步进程针对5位哲学家就餐问题,采用奇数号哲学家先拿起左边的筷子,再去拿右边的筷子;而偶数号哲学家则用相反的方法,进行解决。假设每位哲学家思考5秒,进餐3秒,给出100秒内每位哲学家进餐的

目录

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秒观察效果

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值