哲学家进餐问题描述

假设有五位哲学家围坐在一张圆形餐桌旁,做以下两件事情之一:吃饭,或者思考。吃东西的时候,他们就停止思考,思考的时候也停止吃东西。餐桌中间有一大碗意大利面,每两个哲学家之间有一只餐叉。因为用一只餐叉很难吃到意大利面,所以假设哲学家必须用两只餐叉吃东西。他们只能使用自己左右手边的那两只餐叉。哲学家就餐问题有时也用米饭和筷子而不是意大利面和餐叉来描述,因为很明显,吃米饭必须用两根筷子。

三个求解策略

首先肯定是使用线程来模拟哲学家的,一个线程是一个哲学家,然后要求线程在进行资源竞争时不死锁。

下面给出几种求解策略

1. 利用锁机制,每次保证一个哲学家在吃,哲学家想吃的时候,先测试一下锁,如果能获得锁,则测试一下自己的筷子以及右边的筷子能不能拿,如果能拿则拿起筷子吃,否则阻塞,哲学家思考时测试一下能不能获得互斥锁,如果能则该哲学家放下自己的筷子和右边的筷子。

2. 封装信号量,定义类Semaphore代表信号量,并封装down和up方法,当信号量执行down方法时信号量减一,如果值变为0则阻塞线程,调用up方法使信号量加一,然后定义信号量metux=4来保证同时只有四个哲学家拿筷子,信号量筷子chopsticks []={1,1,1,1,1,…,1},首先metux.down(),保证最多进4个哲学家,然后down自己的筷子,down右边的筷子,如果线程未阻塞,则可以吃饭,吃完后,up右筷子,up自己的筷子,最后metux.up()。

3. 利用封装好的信号量,使用奇偶法。防止哲学家饿死的情况,制定如下规则:

规则: 奇数号的哲学家先拿起右边的筷子再拿起左边的筷子。

偶数号哲学家先拿起左边的筷子,再拿起右边的筷子。

如果哲学家抢到一只筷子,在抢占另一只筷子时失败,则要放弃已经抢占到的资源。

左右两边都抢到筷子的哲学家,吃完放后释放资源。

实现时只需在求解策略二的基础上加个奇偶判断就可以了

C++实现 (JAVA实现的话到处都有)

C++11的thread线程类: C++11引入的跨平台的线程类

C++11 mutex互斥锁:mutex:独占的互斥量

condition_variable条件变量: 条件变量是C++11提供的另外一种用于等待的同步机制,它能阻塞一个或多个线程,直到收到另外一个线程发出的通知或者超时,才会唤醒当前阻塞的线程

代码如下

#include<iostream>
#include<thread>
#include<mutex>
#include<windows.h>
#include<chrono>
#include<condition_variable>
#include<map>
#include<functional>
#include<string>
#include<sstream>
#include<vector>
#include<functional>
#include<ctime>
#include<cstdlib>
#define random(a,b) (rand()%(b-a+1)+a)
using namespace std;
unsigned int MaxN;
namespace Method {
mutex alock;
condition_variable t;
class Semaphore{//信号量的封装 down up操作
private:unsigned int m;
public:Semaphore(unsigned int x):m(x){}Semaphore(){}Semaphore(const Semaphore& t){m = t.m;}~Semaphore(){}void down(){unique_lock<mutex> locker(alock);while(m==0){cout<<"(thread id="<<this_thread::get_id()<<" is wait)"<<endl;t.wait(locker);}m--;}void up(){alock.lock();m++;t.notify_all();alock.unlock();}bool operator == (const Semaphore &t) {return m == t.m;}bool operator !=(const Semaphore &t){return m!=t.m;}bool operator == (const unsigned int &t) {return m == t;}bool operator != (const unsigned int &t){return m!=t;}void operator = (const Semaphore &t){m = t.m;}void operator = (const unsigned int &t){m = t;}Semaphore operator + (const Semaphore &t){return Semaphore(m+t.m);}Semaphore operator + (const unsigned int &t){return Semaphore(m+t);}
};
int Int(thread::id id){stringstream ss;ss<<id;return std::stoi(ss.str());
}
Semaphore mutexs = 4;
Semaphore chopsticks[10000];
//求解策略部分的代码是重点
//求解策略一
auto functionA = []()->void{ //lambda表达式auto eating = []()->void{ //获取线程IDunique_lock<mutex> locker(alock);int current_id = Int(this_thread::get_id())-2;while(chopsticks[current_id]==0||chopsticks[(current_id+1)%MaxN]==0){ //是否能拿自己的筷子和右边的筷子,如果不能则阻塞cout<<"(thread id="<<this_thread::get_id()<<" is wait)"<<endl;t.wait(locker); //阻塞线程}chopsticks[current_id] = 0; //拿自己的筷子chopsticks[(current_id+1)%MaxN] = 0; //拿右边的筷子cout<<"Philosopher"<<current_id<<" are eating (thread id="<<this_thread::get_id()<<" is run)"<<endl;};auto thinking = []()->void{ //思考方法alock.lock(); //获得锁int current_id = Int(this_thread::get_id())-2; //当前线程chopsticks[current_id]=1; //放下自己的筷子chopsticks[(current_id+1)%MaxN]=1; //放下右边的筷子t.notify_all(); //唤醒所有线程cout<<"Philosopher"<<current_id<<" are thinking (thread id="<<this_thread::get_id()<<" is run)"<<endl;alock.unlock(); //释放锁};while(true){ //无限执行线程thinking();chrono::milliseconds s(1000); //睡眠1sthis_thread::sleep_for(s);eating();}};
//求解策略二 auto functionB = []()->void{ //lambda表达式while(true){ //无限执行线程mutexs.down(); //down(mutex)size_t id = Int(this_thread::get_id())-2; //线程IDchopsticks[id].down(); //down(chopsticks[id])chopsticks[(id+1)%MaxN].down(); //down(chopsticks[(id+1)%MaxN])alock.lock();  //锁一下,保证同时只有一个线程往屏幕里输出cout<<"Philosopher"<<id<<" are eating (thread id="<<this_thread::get_id()<<" is run)"<<endl;alock.unlock(); //释放锁chrono::milliseconds s(1000); //睡眠1sthis_thread::sleep_for(s);chopsticks[(id+1)%MaxN].up(); //up(chopsticks[(id+1)%MaxN])chopsticks[id].up(); //up(chopsticks[id])alock.lock(); //锁一下,保证同时只有一个线程往屏幕里输出cout<<"Philosopher"<<id<<" are thinking (thread id="<<this_thread::get_id()<<" is run)"<<endl;alock.unlock(); //释放锁this_thread::sleep_for(s);mutexs.up();}};
//求解策略三
auto functionC = []()->void{ //lambda表达式while(true){ //无限执行线程int id = Int(this_thread::get_id())-2; //获取当前线程if(id%2){//奇数chopsticks[(id+1)%MaxN].down(); //down(chopsticks[(id+1)%MaxN])chopsticks[id].down(); //down(chopsticks[id])alock.lock(); //锁一下,保证同时只有一个线程往屏幕里输出cout<<"Philosopher"<<id<<" are eating (thread id="<<this_thread::get_id()<<" is run)"<<endl;alock.unlock(); //释放锁chrono::milliseconds s(1000); //睡眠1sthis_thread::sleep_for(s);chopsticks[(id+1)%MaxN].up(); //up(chopsticks[(id+1)%MaxN])chopsticks[id].up(); //up(chopsticks[id])}else{//偶数chopsticks[id].down(); //down(chopsticks[id])chopsticks[(id+1)%MaxN].down(); //down(chopsticks[(id+1)%MaxN])alock.lock(); //锁一下,保证同时只有一个线程往屏幕里输出cout<<"Philosopher"<<id<<" are eating (thread id="<<this_thread::get_id()<<" is run)"<<endl;alock.unlock(); //释放锁chrono::milliseconds s(1000); //睡眠1sthis_thread::sleep_for(s);chopsticks[id].up(); //up(chopsticks[id])chopsticks[(id+1)%MaxN].up(); //up(chopsticks[(id+1)%MaxN])}alock.lock(); //锁一下,保证同时只有一个线程往屏幕cout<<"Philosopher"<<id<<" are thinking (thread id="<<this_thread::get_id()<<" is run)"<<endl;alock.unlock(); //释放锁}};}
using namespace Method;
//定义哲学家类
class Philosopher{
private:vector<function<void()> > fns;Philosopher(){}Philosopher(const Philosopher& t){fns = t.fns;}~Philosopher(){}
public:static Philosopher *instance;static Philosopher *of(){if(instance) return instance;return (instance = new Philosopher());}void add(initializer_list<function<void()> >fs){for(auto iter = fs.begin();iter!=fs.end();iter++){fns.push_back(*iter);}}void add(function<void()> t){fns.push_back(t);}function<void() > get(size_t i){return fns[i];}
};Philosopher *Philosopher::instance = 0;
int main()
{Philosopher::of()->add({functionA,functionB,functionC});cout<<"input Philosopher number:"<<endl;cin>>MaxN;cout<<"select method"<<endl;cout<<"1.lock"<<endl;cout<<"2.semaphore use mutex = 4"<<endl;cout<<"3.semaphore use odd even method"<<endl;unsigned int num;cin>>num;vector<thread> phils;for(size_t i=0;i<MaxN;i++){chopsticks[i] = 1;}switch (num) {case 1:for(size_t i=0;i<MaxN;i++){phils.push_back(thread(Philosopher::of()->get(0)));}break;case 2:for(size_t i=0;i<MaxN;i++){phils.push_back(thread(Philosopher::of()->get(1)));}break;case 3:for(size_t i=0;i<MaxN;i++){phils.push_back(thread(Philosopher::of()->get(2)));}break;default:break;}for(auto iter = phils.begin();iter!=phils.end();iter++){iter->join();}return 0;
}

哲学家进餐问题 C++实现相关推荐

  1. IPC之哲学家进餐问题

    A问题: 1965年,Dijkstra提出并解决了一个他称之为哲学家进餐的同步问题. "五个哲学家围坐在一张圆桌周围,每个哲学家的前面都有一份通心面,由于面条很滑,必须使用2把叉子才能夹住. ...

  2. 操作系统(四) | 经典进程的同步问题(生产者--消费者问题、哲学家进餐问题、读者--写者问题)

    文章目录 生产者--消费者问题 分析 实现 哲学家进餐问题 方法一:最多4人同时拿左筷子,最终保证一人能进餐 方法二:同时给左右筷子 解法1:AND信号量 解法2:信号量保护机制 方法三:让奇数先左后 ...

  3. 操作系统:哲学家进餐问题

    哲学家进餐问题 五个哲学家围着一张圆桌,每个哲学家面前放着食物.哲学家的生活有两种交替活动:吃饭以及思考.当一个哲学家吃饭时,需要先拿起自己左右两边的两根筷子,并且一次只能拿起一根筷子. 下面是一种错 ...

  4. 2.3.6 操作系统之进程同步与互斥经典问题(生产者-消费者问题、多生产者-多消费者问题、吸烟者问题、读者-写者问题、哲学家进餐问题)

    文章目录 0.前言 1.生产者-消费者问题 (1)问题描述 (2)问题分析 (3)如何实现? (4)实现互斥的P操作一定要在实现同步的P操作之后 (5)知识回顾与重要考点 2.多生产者-多消费者问题 ...

  5. 操作系统:经典进程同步问题 之 生产者-消费者问题、读者-写者问题、哲学家进餐问题

    在进程同步中,经典的同步问题有:生产者-消费者问题.读者-写者问题.哲学家进餐问题. 一.生产者与消费者问题: 问题描述:使用一个缓冲区来保存物品,只有缓冲区没有满,生产者才可以放入物品:只有缓冲区不 ...

  6. 操作系统之进程管理:15、哲学家进餐问题

    15.哲学家进餐问题 问题描述 解题思路 解决死锁的策略 方案一与方案二 方案三 注 问题描述 解题思路 1.因为需要左手和右手俩只筷子,所以可以直接拿哪只就对哪只上锁 问题:这样的话当每个人都拿走左 ...

  7. and型变量哲学家问题C语言,利用AND型信号量解决哲学家进餐问题,要windows下的C/C++的完整源代码程序。(五个哲学家五只筷子)...

    满意答案 XY_P8q 2013.08.24 采纳率:58%    等级:12 已帮助:5848人 // 哲学家进餐问题 #define WIN32_LEAN_AND_MEAN #include #i ...

  8. 经典同步问题二——哲学家进餐问题

    系列同步问题: 经典同步问题一--生产者和消费者问题 https://blog.csdn.net/weixin_36465540/article/details/105560002 经典同步问题二-- ...

  9. Linux哲学家进餐杀死进程,100分跪求“哲学家就餐问题”在 Linux下运行的源代码(后缀名为.c)!!!...

    如题. | 代码大致如下,当然不能直接使用,我没写P,V操作的函数. # define N 5 /* 哲学家数目 */ # define LEFT (i-1+N)%N /* i的左邻号码 */ # d ...

  10. 用PV操作写出一个不会出现死锁的哲学家进餐问题

    用PV操作写出一个不会出现死锁的哲学家进餐问题 用count限定只能有四个哲学家同时拿起第一根筷子.这样就不会出现没有筷子拿的死锁. semaphore stick[5]={1,1,1,1,1}; s ...

最新文章

  1. C++对象的内存布局1---基础篇----C++ 虚函数表解析
  2. 关于Linux的inode和dentry的一组文章
  3. R包cgdsr下载MSKCC癌症基因组数据
  4. 【资源分享】639页《深度学习:Deep Learning》硬核课程PPT
  5. 找工作 50道编程题Java实现(32-50)
  6. [ An Ac a Day ^_^ ] CodeForces 468A 24 Game 构造
  7. Angular应用里child Component如何向parent Component发送事件
  8. 如何证明CRM WebClient UI上的应用是有状态(Stateful)的
  9. 骁龙660是32位还是64位_微软公布v2004最低处理器要求,放弃32位系统,你的CPU还能支持吗?...
  10. php课程 10-35 php实现文件上传的注意事项是什么
  11. 使用cmd命令创建vue(ivieiw)项目
  12. 深度学习图像分类(十四): EifficientNet系列(V1, V2)
  13. python wxpython常用控件实例
  14. 如何提升串口响应速度
  15. 吉林大学前卫南区计算机宿舍,睡过双一流学生宿舍后,把宿舍照片分享给你们,看看你们想去的学校宿舍长啥样!...
  16. EasyGUI-2:函数基础
  17. 什么是Bom,常用的bom属性又有哪些?
  18. addon游戏_addon_game_mode游戏基本情况设置
  19. CyclicBarrier: 循环栅栏
  20. 【踩坑】Linux java中ftp下载文件,解压文件损坏,以及图片下载打开只显示下载路径的问题

热门文章

  1. OFFICE文档转换到PDF的几种方法与转换效率和性能的简单比较
  2. Windows 10 21H2 版本微软拼音全拼和双拼的快速切换
  3. 13.图像识别与文字处理
  4. 在线解答:怎么拥有TrustedInstaller权限?
  5. html文字纵向导航栏,JS+CSS实现另类带提示效果的竖向导航菜单
  6. Unity -Shader精讲(一)OpenGL,DirectX,CG选择 着色器选择
  7. Latex 环境配置(TexLive + Texstudio)
  8. appium java模拟微信登录,使用Appium 测试微信小程序和微信公众号方法
  9. Astah 三分钟学会躺着画UML时序图
  10. 机器学习必须要会的:方差、标准差、相对标准偏差、正态分布的概念