哲学家进餐问题 C++实现

哲学家进餐问题描述

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

三个求解策略

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

下面给出几种求解策略

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{ //获取线程ID

               unique_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); //睡眠1s
           this_thread::sleep_for(s);
           eating();
       }
   };
//求解策略二 
 auto functionB = []()->void{ //lambda表达式
 
            while(true){ //无限执行线程
                mutexs.down(); //down(mutex)
                size_t id = Int(this_thread::get_id())-2; //线程ID
                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); //睡眠1s
                this_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); //睡眠1s
                    this_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); //睡眠1s
                    this_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;
}

 

猜你喜欢

转载自blog.csdn.net/daydream13580130043/article/details/87941701