首页 > 其他分享 >【操作系统】2.3_11_ 哲学家进餐问题

【操作系统】2.3_11_ 哲学家进餐问题

时间:2024-11-26 15:56:00浏览次数:7  
标签:11 进餐 name int pid 2.3 sem include sems

https://www.bilibili.com/video/BV1YE411D7nH?spm_id_from=333.788.videopod.episodes&vd_source=6c2daed6731190bb7d70296d6b9746bb&p=36

方法1

n个哲学家,n个筷子

创建一个初值为n-1的信号量,保证最多只有n-1个进程并发争抢资源,必有1个筷子资源余留,可以1个进程拿到两支筷子,不会死锁。

这个方法的原子操作是拿取一个筷子的过程

#include <iostream>
#include <semaphore.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/wait.h>
#include <fcntl.h>

#define N 5

using namespace std;

int main(){
    int n = N;
    pid_t pid;

    /************* 信号量 *************/

    //创建信号量,初值n-1;
    char sem_name[20] = "/my_semaphore";
    sem_t* sem = sem_open(sem_name, O_CREAT|O_EXCL, 0666, n-1);
    if (sem == SEM_FAILED){
        if (errno == EEXIST)
        {
            // 如果信号量已存在,尝试删除它
            sem_unlink(sem_name);
            // 等待sem_unlink完成,避免竞态条件
            while (sem_open(sem_name, O_EXCL, 0666, n-1 )!= SEM_FAILED) {
                usleep(1000); // 等待1毫秒
            }
            sem = sem_open(sem_name, O_CREAT|O_EXCL, 0666, n-1);
        }
    }

    /************ 使用信号量保证拿取的原子性 ************/
    sem_t* sems[N]; // 为每个筷子创建互斥量
    for (int i = 0; i < n; i++) {
        sprintf(sem_name, "/sem_%d", i);
        sems[i] = sem_open(sems_name[i], O_CREAT | O_EXCL, 0666, 1);
        if (sems[i] == SEM_FAILED){
            if (errno == EEXIST)
            {
                // 如果信号量已存在,尝试删除它
                sem_unlink(sems_name[i]);
                // 等待sem_unlink完成,避免竞态条件
                while (sem_open(sems_name[i], O_EXCL, 0666, n-1 )!= SEM_FAILED) {
                    usleep(1000); // 等待1毫秒
                }
                sems[i] = sem_open(sems_name[i], O_CREAT|O_EXCL, 0666, 1);
            }
        }
    }

    /********** 哲学家子进程 ***********/
    int i;

    //创建n个哲学家子进程
    for (i = 0; i < n; i++){
        pid = fork();
        if(pid == 0)
            break;
        if (pid < 0)
            perror("fork");
    }

    // 哲学家子进程
    if(pid == 0){

        // 使用信号量取得进餐权限
        sem_wait(sem);

        // 左右筷子编号
        int l = i;
        int r = (i+1)%n;

        // 等待筷子
        sem_wait(sems[l]);
        sem_wait(sems[r]);

        // 模拟进餐
        sleep(1);

        cout << "哲学家 " << i << " 号进餐完毕" << endl;

        // 释放筷子
        sem_post(sems[l]);
        sem_post(sems[r]);

        //释放信号量
        sem_post(sem);

        // 关闭信号量
        if (sem_close(sem) == -1) {
            perror("sem_close");
            exit(1);
        }

        exit(0);
    }

    // 子进程回收
    while (wait(NULL) > 0);
    cout << "哲学家已都进餐完毕" << endl;

    /************* 信号量回收 *************/

    // 完成后关闭信号量
    if (sem_close(sem) == -1) {
        perror("sem_close");
        exit(EXIT_FAILURE);
    }

    // 删除信号量(可选,如果不再需要)
    if (sem_unlink(sem_name) == -1) {
        perror("sem_unlink");
        exit(EXIT_FAILURE);
    }

    // 关闭和删除信号量
    for (int i = 0; i < n; i++) {
        sprintf(sem_name, "/sem_%d", i);
        if (sem_close(sems[i]) == -1) {
            perror("sem_close");
        }
        if (sem_unlink(sem_name) == -1) {
            perror("sem_unlink");
        }
    }

    return 0;
}

方法2

#include <iostream>
#include <semaphore.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/wait.h>
#include <fcntl.h>

#define N 5

using namespace std;

int main(){
    int n = N;
    pid_t pid;
    char sems_name[N][20];

    /************ 使用信号量保证拿取的原子性 ************/
    sem_t* sems[N]; // 为每个筷子创建互斥量
    for (int i = 0; i < n; i++) {
        sprintf(sems_name[i], "/sem_%d", i);
        sems[i] = sem_open(sems_name[i], O_CREAT | O_EXCL, 0666, 1);
        if (sems[i] == SEM_FAILED){
            if (errno == EEXIST)
            {
                // 如果信号量已存在,尝试删除它
                sem_unlink(sems_name[i]);
                // 等待sem_unlink完成,避免竞态条件
                while (sem_open(sems_name[i], O_EXCL, 0666, n-1 )!= SEM_FAILED) {
                    usleep(1000); // 等待1毫秒
                }
                sems[i] = sem_open(sems_name[i], O_CREAT|O_EXCL, 0666, 1);
            }
        }
    }

    /********** 哲学家子进程 ***********/
    int i;

    //创建n个哲学家子进程
    for (i = 0; i < n; i++){
        pid = fork();
        if(pid == 0)
            break;
        if (pid < 0)
            perror("fork");
    }

    // 哲学家子进程
    if(pid == 0){

        // 左右筷子编号
        int l = i;
        int r = (i+1)%n;

        // 等待筷子
        if(i%2==0){
            sem_wait(sems[l]);
            sem_wait(sems[r]);
        }else{
            sem_wait(sems[r]);
            sem_wait(sems[l]);
        }

        // 模拟进餐
        sleep(1);

        cout << "哲学家 " << i << " 号进餐完毕" << endl;

        // 释放筷子
        sem_post(sems[l]);
        sem_post(sems[r]);

        if (sem_close(sems[i]) == -1) {
            perror("sem_close");
            exit(1);
        }

        exit(0);
    }

    // 子进程回收
    while (wait(NULL) > 0);

    cout << "哲学家已都进餐完毕" << endl;

    /************* 信号量回收 *************/

    for (int i = 0; i < n; i++) {
        if (sem_close(sems[i]) == -1) {
            perror("sem_close");
        }
        if (sem_unlink(sems_name[i]) == -1) {
            perror("sem_unlink");
        }
    }

    return 0;
}

方法3

对拿两个筷子这一整个过程进行互斥操作,保证总有一个进程完整的拿到两个筷子。

#include <iostream>
#include <semaphore.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/wait.h>
#include <fcntl.h>

#define N 5

using namespace std;

int main(){
    int n = N;
    pid_t pid;
    const char* sem_name = "/my_semaphore";
    char sems_name[N][20];

    /************* 信号量 *************/

    //创建 拿一双筷子这个过程 的互斥量
    sem_t* sem = sem_open(sem_name, O_CREAT|O_EXCL, 0666, 1);
    if (sem == SEM_FAILED){
        if (errno == EEXIST)
        {
            // 如果信号量已存在,尝试删除它
            sem_unlink(sem_name);
            // 等待sem_unlink完成,避免竞态条件
            while (sem_open(sem_name, O_EXCL, 0666, n-1 )!= SEM_FAILED) {
                usleep(1000); // 等待1毫秒
            }
            sem = sem_open(sem_name, O_CREAT|O_EXCL, 0666, n-1);
        }
    }

    /************ 使用信号量保证拿取的原子性 ************/
    sem_t* sems[N]; // 为每个筷子创建互斥量
    for (int i = 0; i < n; i++) {
        sprintf(sems_name[i], "/sem_%d", i);
        sems[i] = sem_open(sems_name[i], O_CREAT | O_EXCL, 0666, 1);
        if (sems[i] == SEM_FAILED){
            if (errno == EEXIST)
            {
                // 如果信号量已存在,尝试删除它
                sem_unlink(sem_name);
                // 等待sem_unlink完成,避免竞态条件
                while (sem_open(sem_name, O_EXCL, 0666, n-1 )!= SEM_FAILED) {
                    usleep(1000); // 等待1毫秒
                }
                sems[i] = sem_open(sem_name, O_CREAT|O_EXCL, 0666, 1);
            }
        }
    }

    /********** 哲学家子进程 ***********/
    int i;

    //创建n个哲学家子进程
    for (i = 0; i < n; i++){
        pid = fork();
        if(pid == 0)
            break;
        if (pid < 0)
            perror("fork");
    }

    // 哲学家子进程
    if(pid == 0){

        // 使用信号量取得拿一双筷子权限
        sem_wait(sem);

        // 左右筷子编号
        int l = i;
        int r = (i+1)%n;

        // 等待筷子
        sem_wait(sems[l]);
        sem_wait(sems[r]);

        // 模拟进餐
        sleep(1);

        cout << "哲学家 " << i << " 号进餐完毕" << endl;

        // 释放筷子
        sem_post(sems[l]);
        sem_post(sems[r]);

        //释放拿一双筷子这个过程 的信号量
        sem_post(sem);

        // 子进程关闭信号量
        if (sem_close(sem) == -1) {
            perror("sem_close");
            exit(1);
        }
        if (sem_close(sems[i]) == -1) {
            perror("sem_close");
            exit(1);
        }

        exit(0);
    }

    // 子进程回收
    while (wait(NULL) > 0);
    cout << "哲学家已都进餐完毕" << endl;

    /************* 信号量回收 *************/

    // 完成后关闭信号量
    if (sem_close(sem) == -1) {
        perror("sem_close");
        exit(EXIT_FAILURE);
    }
    if (sem_unlink(sem_name) == -1) {
        perror("sem_unlink");
        exit(EXIT_FAILURE);
    }

    for (int i = 0; i < n; i++) {
        if (sem_close(sems[i]) == -1) {
            perror("sem_close");
        }
        if (sem_unlink(sems_name[i]) == -1) {
            perror("sem_unlink");
        }
    }

    return 0;
}

标签:11,进餐,name,int,pid,2.3,sem,include,sems
From: https://www.cnblogs.com/qiuliw/p/18570330

相关文章

  • Docker/DockerHub 国内镜像源/加速列表(11月26日更新-长期维护)
    前言本列表为科研工作者提供docker镜像网站,网络不好的同学可以使用镜像,或者推荐给身边有需要的朋友使用这些docker镜像。注意:仅供学术研究使用。⚠️长期更新,建议收藏!更新日志11月25日新增:https://docker.linkedbus.com(推荐)11月24日新增:https://docke......
  • 金蝶Kingdee Wise ERP 12.3物理机迁移到Hyper-V(Windows Server 2008)
    一、系统迁移详细操作步骤1.数据虚拟化:使用Disk2vhd工具转换磁盘格式为VHD下载Disk2vhd工具:访问Sysinternals官方网站下载Disk2vhd工具,下载地址为:Disk2vhd下载链接。安装并打开Disk2vhd:解压下载的Disk2vhd.zip文件,运行Disk2vhd.exe程序。选择源磁盘并转换为VHD:在Dis......
  • 2024.11.26模拟赛
    昨天也打了模拟赛。但没补没总结。为什么呢。因为懒。今天来了之后先犯困了一个坤小时。犯困的那两个半小时属于是连暴力都没法想怎么去写的那种。好不容易慢慢清醒了,又不想写了。随便打了个T3的暴力,又写了个T1的爆搜,结果爆搜炸了。所以,今天昨天打的都很不怎么样。结果考完之后......
  • 11.26 CW 模拟赛 赛时记录
    看题也是给他绑上\(\rm{Subtask}\)了,这我骗鸡毛分啊感冒也是非常难受,但是事已至此,先读题吧题目背景好看爱看\(\rm{T1}\)图论题,好玩\(\rm{T2}\)大概也是不会做,再说\(\rm{T3}\)难绷,考虑高档暴力\(\rm{T4}\)这个肯定是暴力都难打今天也是\(30\rm{min}......
  • [2024.11.26]NOIP模拟赛
    挂分+不会+暴力场。赛时T1看到大样例里面的输出后意识到这题需要高精。乘法高精讲的时候没听,但是后来不知道从哪看到这就是所谓的加法卷积,所以直接按照卷积的形式写就行了。然后开始看题,感觉特别像打表找规律。看着样例觉得是蛇形填充,写完以后自己造了个样例发现随便组合都......
  • 洛谷 P3524 [POI2011] IMP-Party 题解
    题意给定一个\(n\)个点的无向图,其中\(n\)是\(3\)的倍数。保证该图中含有一个\(\frac{2}{3}n\)个点的团。请你找出一个\(\frac{1}{3}n\)个点的团。\(1\leqn\leq3000\)。题解这种题想不出来是不是可以退役了团中任意两点间必有一条边。因此,如果\(u,v\)两点......
  • 做题随笔:洛谷 P11323
    Solution闲话蒟蒻第一次写题解,若有不当还请海涵。题意$n$类牌,每类$v_i$张,每次可出一张(单牌),同类的二张(对子),类A的三张和类B的一张(三带一),同类的四张(炸),求出完牌的最少出牌次数。分析逐类考虑:首先,某类牌多于4张时无脑炸不是最优(本蒟蒻在这里先死了10分钟),只要看一眼样例的例一不......
  • 【R安装】R语言的详细安装及环境配置(2024年11月)
    目录R及Rstudio下载R下载Rstudio下载R及Rstudio安装R安装Rtools安装Rstudio安装运行RStudio通过RStudio配置使用特定的R版本参考R及Rstudio下载R下载R官网-TheRProjectforStatisticalComputing点击【downloadR】,进入下载界面:选择需要的镜像版本,如下:......
  • 985研一学习日记 - 2024.11.25
    一个人内耗,说明他活在过去;一个人焦虑,说明他活在未来。只有当一个人平静时,他才活在现在。日常1、起床2、健身3、LeetCode刷了1题单词拆分给定一个非空字符串s和一个包含非空单词的列表wordDict,判定s是否可以被空格拆分为一个或多个在字典中出现的单词。该问题......
  • 11.25 周一日常
    11.25周一日常Q1.1200给定x,y,k,k次操作,每次操作:x++,若x可被y整除,x一直除以y。问最终x的值。(x,y,k≤1e9)Q2.1400给定一等差数列a,每次操作:令最大值=mex{a}。问是否可以将a变成0~n-1的排列和最小操作次数。(1e18)Q3.1600给定一数组和lim,设操作l,r:i:l->r,令s=0,s+=a[i];每一步如......