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

news/2024/11/28 4:45:38/文章来源:https://www.cnblogs.com/qiuliw/p/18570330

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 5using 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 5using 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 5using 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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/841671.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PhpWebStudy运行Laravel

创建Laravel项目​ 如果你想使用已存在的项目. 你可以跳过此步骤. 继续 创建站点 你可以使用Composer创建Laravel项目 shell composer create-project laravel/laravel example-app当然,FlyEnv也提供了快速创建laravel项目的方法。在站点面板中. 点击 新建项目选择项目保存位置…

Docker/DockerHub 国内镜像源/加速列表(11月26日更新-长期维护)

此文维护一个列表收录无需限定条件的Docker Hub镜像源,感谢这些公益服务者。6月6日,上海交大的 Docker Hub 镜像加速宣布因监管要求被下架,Docker hub 被封无法访问。前言本列表为科研工作者提供 docker 镜像网站,网络不好的同学可以使用镜像,或者推荐给身边有需要的朋友使…

Jenkin window bat批处理脚本如何 获取json对象返回值数据

前两天有这么个小需求: 在cmd中运行某测试工具后/请求某个api后,会返回一个json结果,其中有一个参数的值每次都变且经常要用,正常情况复制粘贴就好了,但这个值非常长,配上cmd的标记+粘贴的行为,就很酸爽了。然后就想快速提取这个值,顺着cmd的这个思路,就走上了批处理的…

jndi注入

jndi注入 jndi简单来说是提供一个查找服务,你可以通过字符串找到对应的对象。而jndi需要有服务的提供者,也就是是谁来提供这些对象。jndi只是负责名字->对象的查找,而不提供对象。 可以作为服务提供者的: Lightweight Directory Access Protocol (LDAP) 轻量级目录访问协…

《刚刚问世》系列初窥篇-Java+Playwright自动化测试-6- 元素基础定位方式-上篇 (详细教程)

1.简介 从这篇文章开始,就开始要介绍UI自动化核心的内容,也是最困难的部分了,就是:定位元素,并去对定位到的元素进行一系列相关的操作。想要对元素进行操作,第一步,也是最重要的一步,就是要找到这个元素,如果连元素都定位不到,后续什么操作都是无用功,都是扯淡,因此…

【类的默认成员函数】构造函数析构函数【C++】

【类的默认成员函数】构造函数&&析构函数【C++】 任何一个类在我们不写的情况下,都会自动生成6个默认成员函数构造函数:初始化(不是开空间!) 日常实操中最好自己写一个!!!!!!!! Date() {_year = 1;_month = 1;_day = 1; }特点 (1)函数名和类名相同 (2)…

Notepad++汉化教程

Notepad++系统只带了中文语言包,不需要像其他软件一样破解 1、打开Notepad++(通过文本文件右键选择以Notepad++打开或者找到Notepad++的快捷方式打开)。 2、菜单栏找到settings–>Preferences(首选项)。 3、找到General 右侧Localization选择简体中文,可以看到语言直接变…

文档解析Docling、Marker测评

Docling https://github.com/DS4SD/docling 环境安装 直接使用文档中的 pip install docling无法使用,因为torch和nvidia过高,与当前服务器版本不匹配,最好是低于当前服务器版本比较保险python第三方库中nvidia开头的版本需要小于12.2,如果使用12.4无法使用 安装步骤: pip…

explicit关键字【C++】

explicit关键字【C++】 用来修饰只有一个参数的类构造函数,以表明该构造函数是显式的,而非隐式的 禁止类对象之间的隐式转换,以及禁止隐式调用拷贝构造函数 隐式类型转换 int i = 1; double d = i;d被i赋值时 【编译器会做】 在中间产生一个临时变量 再通过这个临时对象进行…

快手观看时长建模:CREAD

将观看时长作为连续值预测,会带来“回归问题”,即会放大对异常值和潜在预测偏差的敏感性,常见的一种方法是把时长分段转为分类问题来预估,CREAD正是提出了一种回归转分类的处理方法。 CREAD的流程如下图所示,把观看时长分为M个桶,在每个桶内预估 P(y>t|x)的概率 经过推…

.NET9 EFcore支持早期MSSQL数据库 ROW_NUMBER()分页

前言 NET程序员是很幸福的,MS在上个月发布了NET9.0RTM,带来了不少的新特性,但是呢,我们是不是还有很多同学软硬件都还没更上,比如,自己的电脑还在跑Win7,公司服务器还在跑MSSQL2005-2008的! 这不就引入了我们本文要探索的问题,因为MS早在EFcore3.1后就不再内置支持ROW_NUMBER()…

hhdb数据库介绍(9-8)

高可用服务 计算节点负载均衡 HHDB Server支持多计算节点集群的节点自治。以下简称计算节点集群中Primary状态的计算节点为Primary计算节点;计算节点集群中Secondary状态的计算节点为Secondary计算节点。Primary和Secondary计算节点的数据服务完全对等,均支持所有类型的数据操…