哲学家进餐问题

哲学家进餐问题

由荷兰学者Dijkstra提出的哲学家进餐问题(The Dinning Philosophers Problem)是经典的同步问题之一

有五个哲学家,他们的生活方式是交替地进行思考和进餐,哲学家们共用一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五支筷子,平时哲学家进行思考,饥饿时便试图取其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐,该哲学家进餐完毕后,放下左右两只筷子又继续思考。
约束条件
(1)只有拿到两只筷子时,哲学家才能吃饭。
(2)如果筷子已被别人拿走,则必须等别人吃完之后才能拿到筷子。
(3)任一哲学家在自己未拿到两只筷子吃完饭前,不会放下手中已经拿到的筷子。

接下来用的至少需要C++11

死锁

整体思路就是拿左边上锁,拿右边上锁

但是有可能5个哲学家同时拿,这就导致他们拿完了左边,每个人都无法拿右边,就g了
尤其是拿完了左边,开始sleep,sleep越久就越有可能死锁

#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>int getThinkTime(){return 1;
}int getEatTime(){return 1;
}void think(size_t id){std::cout<< id<< " starts thinking."<< std::endl;std::this_thread::sleep_for(std::chrono::seconds(getThinkTime()));std::cout<< id<< " all done thinking."<< std::endl;
}void eat(size_t id, std::mutex& left, std::mutex& right){left.lock();std::this_thread::sleep_for(std::chrono::seconds(2));right.lock();std::cout<< id<< " starts eating om nom nom nom."<< std::endl;std::this_thread::sleep_for(std::chrono::seconds(getEatTime()));std::cout<< id<< " all done eating."<< std::endl;left.unlock();right.unlock();
}void philosopher(size_t id, std::mutex& left, std::mutex& right){for(size_t i = 0; i < 3; ++i){think(id);eat(id, left, right);}
}int main(){std::mutex forks[5];std::thread philosophers[5];for(size_t i = 0; i < 5; ++i){philosophers[i] = std::thread(philosopher, i, ref(forks[i]), ref(forks[(i + 1) % 5]));}for(auto& p:philosophers)p.join();return 0;
}

奇偶

奇数先拿左边,偶数先拿右边

那么奇数人就是拿0, 2
偶数人拿1, 3, 0
这样0是不能同时拿,就不会死锁了

#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>int getThinkTime(){return 1;
}int getEatTime(){return 1;
}void think(size_t id){std::cout<< id<< " starts thinking."<< std::endl;std::this_thread::sleep_for(std::chrono::seconds(getThinkTime()));std::cout<< id<< " all done thinking."<< std::endl;
}void eat(size_t id, std::mutex& left, std::mutex& right){if(id & 1){left.lock();std::this_thread::sleep_for(std::chrono::seconds(2));right.lock();}else{right.lock();std::this_thread::sleep_for(std::chrono::seconds(2));left.lock();}std::cout<< id<< " starts eating om nom nom nom."<< std::endl;std::this_thread::sleep_for(std::chrono::seconds(getEatTime()));std::cout<< id<< " all done eating."<< std::endl;left.unlock();right.unlock();
}void philosopher(size_t id, std::mutex& left, std::mutex& right){for(size_t i = 0; i < 3; ++i){think(id);eat(id, left, right);}
}int main(){std::mutex forks[5];std::thread philosophers[5];for(size_t i = 0; i < 5; ++i){philosophers[i] = std::thread(philosopher, i, ref(forks[i]), ref(forks[(i + 1) % 5]));}for(auto& p:philosophers)p.join();return 0;
}

条件变量

简单来说就是最多同时有4个哲学家操作,其实1-4都是可以的,只要不要让5个哲学家一起操作就行

我这里用的condition_variable_any,不仅可以操作lock_guard,还可以操作unique_lock
如果用condition_variable,那就只能操作unique_lock

#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>
#include <condition_variable>int getThinkTime(){return 1;
}int getEatTime(){return 1;
}void think(size_t id){std::cout<< id<< " starts thinking."<< std::endl;std::this_thread::sleep_for(std::chrono::seconds(getThinkTime()));std::cout<< id<< " all done thinking."<< std::endl;
}void waitForPermission(size_t& permits, std::condition_variable_any& cv, std::mutex& m){std::lock_guard<std::mutex> lg(m);cv.wait(m, [&permits](){return permits > 0;});--permits;
}void grantPermission(size_t& permits, std::condition_variable_any& cv, std::mutex& m){std::lock_guard<std::mutex> lg(m);++permits;if(permits == 1)cv.notify_all();
}void eat(size_t id, std::mutex& left, std::mutex& right, size_t& permits, std::condition_variable_any& cv, std::mutex& m){waitForPermission(permits, cv, m);left.lock();std::this_thread::sleep_for(std::chrono::seconds(2));right.lock();std::cout<< id<< " starts eating om nom nom nom."<< std::endl;std::this_thread::sleep_for(std::chrono::seconds(getEatTime()));std::cout<< id<< " all done eating."<< std::endl;grantPermission(permits, cv, m);left.unlock();right.unlock();
}void philosopher(size_t id, std::mutex& left, std::mutex& right, size_t& permits, std::condition_variable_any& cv, std::mutex& m){for(size_t i = 0; i < 3; ++i){think(id);eat(id, left, right, permits, cv, m);}
}int main(){size_t permits = 4;std::condition_variable_any cv;std::mutex forks[5], m;std::thread philosophers[5];for(size_t i = 0; i < 5; ++i){philosophers[i] = std::thread(philosopher, i, std::ref(forks[i]), std::ref(forks[(i + 1) % 5]), std::ref(permits), std::ref(cv), std::ref(m));}for(auto& p:philosophers)p.join();return 0;
}

信号量

这个需要C++20,思路和上面差不多

#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>
#include <semaphore>const int N = 5;int getThinkTime(){return 1;
}int getEatTime(){return 1;
}void think(size_t id){std::cout<< id<< " starts thinking."<< std::endl;std::this_thread::sleep_for(std::chrono::seconds(getThinkTime()));std::cout<< id<< " all done thinking."<< std::endl;
}void eat(size_t id, std::mutex& left, std::mutex& right, std::counting_semaphore<N - 1>& permits){permits.acquire();left.lock();std::this_thread::sleep_for(std::chrono::seconds(2));right.lock();std::cout<< id<< " starts eating om nom nom nom."<< std::endl;std::this_thread::sleep_for(std::chrono::seconds(getEatTime()));std::cout<< id<< " all done eating."<< std::endl;permits.release();left.unlock();right.unlock();
}void philosopher(size_t id, std::mutex& left, std::mutex& right, std::counting_semaphore<N - 1>& permits){for(size_t i = 0; i < 3; ++i){think(id);eat(id, left, right, permits);}
}int main(){std::counting_semaphore<N - 1> permits(4);std::mutex forks[5];std::thread philosophers[5];for(size_t i = 0; i < 5; ++i){philosophers[i] = std::thread(philosopher, i, std::ref(forks[i]), std::ref(forks[(i + 1) % 5]), std::ref(permits));}for(auto& p:philosophers)p.join();return 0;
}

Leetcode1226

奇偶

class DiningPhilosophers {
public:const int N = 5;vector<mutex> forks;DiningPhilosophers():forks(N) {}void wantsToEat(int philosopher,function<void()> pickLeftFork,function<void()> pickRightFork,function<void()> eat,function<void()> putLeftFork,function<void()> putRightFork) {int left = philosopher, right = (philosopher + 1) % N;if(philosopher & 1){forks[left].lock();forks[right].lock();pickLeftFork();pickRightFork();}else{forks[right].lock();forks[left].lock();pickRightFork();pickLeftFork();}eat();putLeftFork();putRightFork();forks[left].unlock();forks[right].unlock();}
};

条件变量

其实就是模拟信号量

这里注意

[&cnt = cnt](){return cnt > 0;}

这个匿名函数需要C++14,低于14可以[this],不然lambda搜索不到cnt

class Semaphore{
private:int cnt;mutex m;condition_variable_any cv;
public:Semaphore(int cnt):cnt(cnt){}void wait(){lock_guard<mutex> lg(m);cv.wait(m, [&cnt = cnt](){return cnt > 0;});--cnt;}void signal(){lock_guard<mutex> lg(m);++cnt;if(cnt == 1)cv.notify_all();}
};
class DiningPhilosophers {
public:const static int N = 5;vector<mutex> forks;Semaphore permits;DiningPhilosophers():forks(N), permits(N - 1) {}void wantsToEat(int philosopher,function<void()> pickLeftFork,function<void()> pickRightFork,function<void()> eat,function<void()> putLeftFork,function<void()> putRightFork) {int left = philosopher, right = (philosopher + 1) % N;permits.wait();forks[left].lock();forks[right].lock();pickLeftFork();pickRightFork();eat();putLeftFork();putRightFork();permits.signal();forks[left].unlock();forks[right].unlock();}
};

信号量

需要C++20

class DiningPhilosophers {
public:const static int N = 5;vector<mutex> forks;counting_semaphore<N - 1> permits;DiningPhilosophers():forks(N), permits(N - 1) {}void wantsToEat(int philosopher,function<void()> pickLeftFork,function<void()> pickRightFork,function<void()> eat,function<void()> putLeftFork,function<void()> putRightFork) {int left = philosopher, right = (philosopher + 1) % N;permits.acquire();forks[left].lock();forks[right].lock();pickLeftFork();pickRightFork();eat();putLeftFork();putRightFork();permits.release();forks[left].unlock();forks[right].unlock();}
};

https://web.stanford.edu/class/archive/cs/cs110/cs110.1204/static/lectures/10-threads-and-mutexes.pdf
https://blog.csdn.net/tomjobs/article/details/113921067

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

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

相关文章

HTML5+CSS3+JS小实例:数字滑动选择控件

实例:数字滑动选择控件 技术栈:HTML+CSS+JS 效果: 源码: 【HTML】 <!DOCTYPE html> <html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta name="viewport" content=&quo…

IPtables防火墙详解

一、IPtables介绍 iptables是unix/linux自带的一款开放源代码的完全自由的基于包过滤(对OSI模型的四层或者是四层以下进行过滤)的防火墙工具&#xff0c;它的功能十分强大&#xff0c;使用非常灵活&#xff0c;可以对流入和流出服务器的数据包进行很精细的控制。主要针对网络访…

最全最详细ChatGPT角色预设词教程,Prompt分享

使用指南 1、可直复制使用 2、可以前往已经添加好Prompt预设的AI系统测试使用&#xff08;可自定义添加使用&#xff09; 雅思写作考官 我希望你假定自己是雅思写作考官&#xff0c;根据雅思评判标准&#xff0c;按我给你的雅思考题和对应答案给我评分&#xff0c;并且按照雅…

开会做笔记的时候用什么软件比较好?

在工作生涯中&#xff0c;会经历很多大大小小的会议&#xff0c;而如何快速准确记录下会议上重要的内容&#xff0c;成了很多上班族的必修课。在会上做笔记&#xff0c;选择什么样的工具才能事半功倍&#xff0c;成了一个值得深思的问题。而经过一段时间的测评后&#xff0c;我…

SHEIN出口儿童玩具加拿大站CCPSA安全标准办理解析

儿童玩具是为特定年龄组的儿童设计和制造的,其特点与儿童的年龄和智力阶段有关。儿童玩具的使用以一定的适应能力为前提。儿童玩具上亚马逊加拿大站需要办理CCPSA安全标准&#xff0c;才能在SHEIN\亚马逊上销售。 CCPSA安全标准&#xff0c;必须由 ISO 17025 认可的检测实验室…

Postman:专业API测试工具,提升Mac用户体验

如果你是一名开发人员或测试工程师&#xff0c;那么你一定知道Postman。这是一个广泛使用的API测试工具&#xff0c;适用于Windows、Mac和Linux系统。今天&#xff0c;我们要重点介绍Postman的Mac版本&#xff0c;以及为什么它是你进行API测试的理想选择。 一、强大的功能和易…

在 AlmaLinux9 上安装Oracle Database 23c

在 AlmaLinux9 上安装Oracle Database 23c 0. 下载 Oracle Database 23c 安装文件1. 安装 Oracle Database 23c3. 连接 Oracle Database 23c4. &#xff08;谨慎&#xff09;卸载 Oracle Database 23c 0. 下载 Oracle Database 23c 安装文件 版权问题&#xff0c;下载地址请等待…

工单派单管理系统有什么用?企业如何提升生产效率与产品质量?

在当今竞争激烈的市场环境中&#xff0c;企业需要一个高效、精准的管理工具来提升生产制造的效率和品质。工单派单管理系统正是这样一种工具&#xff0c;能够实现生产计划、任务分配、进度追踪、工时掌控等环节的优化&#xff0c;提高整体生产运营的效率和精度。 一、工单生成 …

残疾人服务满意度提升方案 | 群狼调研(长沙第三方调查)

提升残疾人服务满意度需要综合考虑服务的各个方面&#xff0c;从可访问性、沟通、个性化服务等多个角度入手。以下是一些可能的残疾人服务满意度提升方案&#xff1a; 1. 提升可访问性&#xff1a; • 确保服务场所、信息传递等方面的设施和信息对残疾人来说是可访问的。 •…

Pycharm 初学者使用教程Ⅰ

目录 1. 下载 Pycharm2. 安装 Pycharm3.打开 Pycharm4.初始化配置界面ProjectsCustomizePluginsLearn 关联博文 1. 下载 Pycharm 下载链接&#xff1a;https://www.jetbrains.com/pycharm/download/?sectionwindows 在下载链接网页中&#xff0c;首先看到的是PyCharm Profes…

Dockerfile构建Python-Ubuntu-Opencv环境

简介 由于最近这段时间Docker官方的python镜像中的apt-key过期了导致apt无法使用只能从原始的Ubuntu镜像开始构建python环境 Dockerfile FROM ubuntu:20.04 AS builder-image# 将安装过程设置为非交互式防止卡死 ENV DEBIAN_FRONTENDnoninteractiveRUN apt-get update &…

计算机网络(二)

&#xff08;八&#xff09;客户端软件设计的细节 A、解析协议号 客户端可能会需要通过协议名指定协议&#xff0c;但是Socket接口是用协议号指定的&#xff0c;这时候我们就需要使用getprotobyname()函数实现协议名到协议号的转换&#xff0c;该函数会返回一个指向protoent的…

深度学习实战62-强化学习在简单游戏领域的应用,利用强化学习训练Agent程序的代码和步骤

大家好,我是微学AI,今天给大家介绍一下深度学习实战62-强化学习在简单游戏领域的应用,利用强化学习训练Agent程序的代码和步骤。本文介绍了如何利用强化学习构建智能体程序,而无需使用启发式算法。通过玩游戏并尝试最大化获胜率,我们可以逐渐完善Agent程序的策略。强化学习…

【开源威胁情报挖掘2】开源威胁情报融合评价

基于开源信息平台的威胁情报挖掘综述 写在最前面4 开源威胁情报融合评价开源威胁情报的特征与挑战4.1 开源威胁情报数据融合融合处理方法 4.1 开源威胁情报的质量评价4.1.1 一致性分析本体的定义与组成本体构建的层次 4.1.2 去伪去重4.1.3 数据融合分析 4.2 开源威胁情报质量及…

谈谈Redis的数据淘汰策略

目录 写在前面 数据淘汰策略 不进行数据淘汰策略 进行数据淘汰策略 LRU和LFU的对比 写在前面 我们都知道redis中的数据是采访在内存中的&#xff0c;在从redis中增删查改数据时&#xff0c;都是操作的内存中的数据&#xff0c;而内存是有限的&#xff0c;当内存被占满了之…

嗨,你开始养生了吗?

一、年少轻狂 曾几何时我们意气风发&#xff0c;矫健如飞&#xff0c;吃大碗的面&#xff0c;熬最晚的夜&#xff0c;好像十二点之前睡觉都是浪费生命&#xff0c;刚工作时加班对我们来说那就是小儿科&#xff0c;一点都不觉得累&#xff0c;加完班回来还要看一会手机才能睡着…

[SWPUCTF 2021 新生赛]PseudoProtocols

题目很明确了就是伪协议 php://filter/convert.base64-encode/resourcehint.php 提交的伪协议的内容需要是 I want flag&#xff0c;就会echo flag 方法1&#xff1a;adata://text/plain,I want flag 方法2&#xff1a;adata://text/plain;base64,SSB3YW50IGZsYWc

KAO2 入门到熟练 看这一篇文章就够了

KOA 介绍 官网地址&#xff1a; https://koa.bootcss.com/ Koa 是一个新的 web 框架&#xff0c;由 Express 幕后的原班人马打造&#xff0c; 致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。 通过利用 async 函数&#xff0c;Koa 帮你丢弃回调…

万字解析设计模式之策略模式、命令模式

一、策略模式 1.1概述 先看下面的图片&#xff0c;我们去旅游选择出行模式有很多种&#xff0c;可以骑自行车、可以坐汽车、可以坐火车、可以坐飞机。 策略模式&#xff08;Strategy Pattern&#xff09;是一个行为型设计模式&#xff0c;它定义了一组算法家族&#xff0c;分…

看Spring源码不得不会的@Enable模块驱动实现原理讲解

这篇文章我想和你聊一聊 spring的Enable模块驱动的实现原理。 在我们平时使用spring的过程中&#xff0c;如果想要加个定时任务的功能&#xff0c;那么就需要加注解EnableScheduling&#xff0c;如果想使用异步的功能&#xff0c;那就要加EnableScheduling注解&#xff0c;其实…