精华内容
下载资源
问答
  • 哲学家吃饭问题

    2011-12-19 14:45:52
    哲学家思考后,过一定的时间就会饥饿,饥饿之后就想吃饭吃饭后再思考。房间里有一张圆桌,桌子周围放有6把椅子,分别属于6位哲学家,每两位哲学家之间有1支筷子,哲学家进食时必须同时使用左右两支筷子。
  • C++哲学家吃饭问题

    2021-05-29 20:31:29
    利用C++11对哲学家吃饭问题进行超简单实现

    问题描述

    摘自百度

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


    代码实现

    死锁的情况

    const int philosopher_num = 5;
    std::mutex chopsticks[philosopher_num];
    
    void Philosopher(int pid){
        while (true) {
            std::unique_lock<std::mutex>lk_l(chopsticks[pid-1]);//取左边的筷子
            std::this_thread::sleep_for(100ms);//更快出现死锁(如果有的话)
            std::unique_lock<std::mutex>lk_r(chopsticks[pid % philosopher_num]);//取右边的筷子
            cout << "哲学家"<<pid<<" 线程id" << std::this_thread::get_id() <<"吃饭了" << endl;
        }
    }
    
    int main()
    {
        vector<thread> threads;
        for (int i = 0; i < philosopher_num; ++i) {
            threads.push_back(thread(Philosopher,i+1));
        }
    
        for (int i = 0; i < philosopher_num; ++i) {
            threads[i].join();
        }
    }
    

    解决的情况1

    拿两双筷子才吃饭

    void Philosopher(int pid) {
    	while (true) {
    		std::unique_lock<std::mutex>lk_l(chopsticks[pid - 1],std::defer_lock);//取左边的筷子
            std::this_thread::sleep_for(100ms);//更快出现死锁(如果有的话)
    		std::unique_lock<std::mutex>lk_r(chopsticks[pid % philosopher_num], std::defer_lock);//取右边的筷子
            std::lock(lk_l, lk_r);
    		cout << "哲学家" << pid << " 线程id" << std::this_thread::get_id() << "吃饭了" << endl;
    	}
    }
    

    解决的情况2

    只允许4位哲学家同时吃饭

    int eating_num = 0;
    std::mutex can_eat;
    std::condition_variable num_eating;
    
    void Philosopher(int pid) {
        while (true) {
            //能否吃饭
            std::unique_lock<std::mutex>lk_e(can_eat);
            num_eating.wait(lk_e, []() {return eating_num < philosopher_num - 1; });
            eating_num++;
            lk_e.unlock();
    
            std::unique_lock<std::mutex>lk_l(chopsticks[pid - 1]);//取左边的筷子
            std::this_thread::sleep_for(100ms);//更快出现死锁(如果有的话)
            std::unique_lock<std::mutex>lk_r(chopsticks[pid % philosopher_num]);//取右边的筷子
            cout << "哲学家" << pid << " 线程id" << std::this_thread::get_id() << "吃饭了" << endl;
    
            lk_e.lock();
            eating_num--;
            lk_e.unlock();
            num_eating.notify_all();
        }
    }
    

    解决的情况3

    奇数哲学家先拿左边的筷子,偶数哲学家先拿右边筷子。这种方法思想和实现上最简单,不需要使用别的技术。

    void Philosopher(int pid){
        while (true) {
            cout << pid - 1 << endl;
            if (pid % 2 == 0) {
                std::unique_lock<std::mutex>lk_l(chopsticks[pid - 1]);//取左边的筷子
                std::this_thread::sleep_for(100ms);//更快出现死锁(如果有的话)
                std::unique_lock<std::mutex>lk_r(chopsticks[pid % philosopher_num]);//取右边的筷子
            }
            else {
                std::unique_lock<std::mutex>lk_r(chopsticks[pid % philosopher_num]);//取右边的筷子
                std::this_thread::sleep_for(100ms);//更快出现死锁(如果有的话)
                std::unique_lock<std::mutex>lk_l(chopsticks[pid - 1]);//取左边的筷子
            }
    
            cout << "哲学家"<<pid<<" 线程id" << std::this_thread::get_id() <<"吃饭了" << endl;
        }
    }
    

    使用C++11的锁机制解决哲学家吃饭问题太简单了

    展开全文
  • 哲学家吃饭问题(vc代码) 哲学家吃饭问题(vc代码) 哲学家吃饭问题(vc代码) 哲学家吃饭问题(vc代码) 哲学家吃饭问题(vc代码)
  • Linux C哲学家吃饭问题

    2021-05-24 21:54:08
    哲学家吃饭问题哲学家问题线程中的信号量无名信号量的定义:P操作:使信号量-1V操作:使信号量+1正常代码(可能发生死锁现象)解法1解法2 哲学家问题 有五个哲学家绕着圆桌坐,每个哲学家面前有一盘面,两人之间有一...

    哲学家问题

    有五个哲学家绕着圆桌坐,每个哲学家面前有一盘面,两人之间有一支筷子,这样每个哲学家左右各有一支筷子。哲学家有2个状态,思考或者拿起筷子吃饭。如果哲学家拿到一只筷子,不能吃饭,直到拿到2只才能吃饭,并且一次只能拿起身边的一支筷子。一旦拿起便不会放下筷子直到把饭吃完,此时才把这双筷子放回原处。如果,很不幸地,每个哲学家拿起他或她左边的筷子,那么就没有人可以吃到饭了(死锁)。哲学家进餐问题是一个多线程运用的经典例子,涉及到线程同步/互斥,临界区访问问题以及死锁问题。我们要做的就是防止死锁。

    线程中的信号量

    这里的信号量和我另一篇博客中进程间的通信的博客里的信号量是不同的,区别可以参考我找到的一篇博客进程的信号量和线程的信号量
    信号量是一个计数器,可以用来控制多个进程或线程对共享资源的访问。它常作为一种锁机制,防止某进程或线程在访问共享资源时,其他进程或线程也在访问,因此主要作为进程间或同一进程间不同线程之间的同步机制。当信号量大于0时表示可以使用的资源数量,小于0时表示等待使用资源的进程或线程个数。信号量的值仅能通过PV操作来改变。

    无名信号量的定义:

    #include <semaphore.h>
    int sem_init(sem_t *sem, int pshared, unsigned int value);
    

    sem为指向信号量结构的一个指针;pshared不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享;value给出了信号量的初始值。

    P操作:使信号量-1

    #include <semaphore.h>
    int sem_wait(sem_t *sem);
    

    sem为指向信号量结构的一个指针;

    V操作:使信号量+1

    #include <semaphore.h>
    int sem_post(sem_t *sem);
    

    sem为指向信号量结构的一个指针;

    正常代码(可能发生死锁现象)

    每一根筷子都是一个信号量,有人拿就进行P操作对拿起的筷子-1,吃完进行V操作对放下的筷子+1。
    我们这里把哲学家设置都先拿左边的筷子,拿到后再拿右边的筷子,没拿到就等待别人放下筷子。
    哲学家吃饭.c

    /***************************************
     * 正常哲学家吃饭
     * 可能会造成死锁
     * ************************************/
    #include <stdio.h> 
    #include <pthread.h> 
    #include <unistd.h>
    #include <semaphore.h> 
    
    sem_t sem[6];
    
    void thread_1(void *arg)
    {
        int sum = 0;
        sem_wait(&sem[1]);
        printf("111拿起1筷子\t");
        sem_wait(&sem[2]);
        printf("111拿起2筷子\t");
        printf("哲学家1吃完!\t");
        sem_post(&sem[1]);
        printf("111释放1筷子\t");
        sem_post(&sem[2]);
        printf("111释放2筷子\n");
    }
    
    void thread_2(void *arg)
    {
        sem_wait(&sem[2]);
        printf("222拿起2筷子\t");
        sem_wait(&sem[3]);
        printf("222拿起3筷子\t");
        printf("哲学家2吃完!\t");
        sem_post(&sem[2]);
        printf("222释放2筷子\t");
        sem_post(&sem[3]);
        printf("222释放3筷子\n");
    }
    
    void thread_3(void *arg)
    {
        sem_wait(&sem[3]);
        printf("333拿起3筷子\t");
        sem_wait(&sem[4]);
        printf("333拿起4筷子\t");
        printf("哲学家3吃完!\t");
        sem_post(&sem[3]);
        printf("333释放3筷子\t");
        sem_post(&sem[4]);
        printf("333释放4筷子\n");
    }
    
    void thread_4(void *arg)
    {
        //printf("*");
        sem_wait(&sem[4]);
        printf("444拿起4筷子\t");
        //printf("A");
        sem_wait(&sem[5]);
        printf("444拿起5筷子\t");
        printf("哲学家4吃完!\t");
        sem_post(&sem[4]);
        printf("444释放4筷子\t");
        sem_post(&sem[5]);
        printf("444释放5筷子\n");
    }
    
    void thread_5(void *arg)
    {
        //printf("**");
        sem_wait(&sem[5]);
        printf("555拿起5筷子\t");
        //printf("AA");
        sem_wait(&sem[1]);
        printf("555拿起1筷子\t");
        printf("哲学家5吃完!\t");
        sem_post(&sem[5]);
        printf("555释放5筷子\t");
        sem_post(&sem[1]);
        printf("555释放1筷子\n");
    }
    
    int main()
    {
        pthread_t thread1;
        pthread_t thread2;
        pthread_t thread3;
        pthread_t thread4;
        pthread_t thread5;
    
        sem_init(&sem[1], 0, 1);              //信号量设置为1,表示一次只能一个人拿该筷子
        sem_init(&sem[2], 0, 1);              //信号量设置为1,表示一次只能一个人拿该筷子
        sem_init(&sem[3], 0, 1);              //信号量设置为1,表示一次只能一个人拿该筷子
        sem_init(&sem[4], 0, 1);              //信号量设置为1,表示一次只能一个人拿该筷子
        sem_init(&sem[5], 0, 1);              //信号量设置为1,表示一次只能一个人拿该筷子
    
        int ret;
    
        //printf("%d\n%d\n%d\n%d\n%d\n",sem[1],sem[2],sem[3],sem[4],sem[5]);
    
        ret = pthread_create(&thread1, NULL, (void *)thread_1, NULL);
        if(ret != 0)
        {
            printf("Thread_1 wrong!\n");
        }
    
        ret = pthread_create(&thread2, NULL, (void *)thread_2, NULL);
        if(ret != 0)
        {
            printf("Thread_2 wrong!\n");
        }
    
        ret = pthread_create(&thread3, NULL, (void *)thread_3, NULL);
        if(ret != 0)
        {
            printf("Thread_3 wrong!\n");
        }
    
        ret = pthread_create(&thread4, NULL, (void *)thread_4, NULL);
        if(ret != 0)
        {
            printf("Thread_4 wrong!\n");
        }
    
        ret = pthread_create(&thread5, NULL, (void *)thread_5, NULL);
        if(ret != 0)
        {
            printf("Thread_5 wrong!\n");
        }
    
        pthread_join(thread1, NULL);
        pthread_join(thread2, NULL);
        pthread_join(thread3, NULL);
        pthread_join(thread4, NULL);
        pthread_join(thread5, NULL);
    
        sem_destroy(&sem[1]);
        sem_destroy(&sem[2]);
        sem_destroy(&sem[3]);
        sem_destroy(&sem[4]);
        sem_destroy(&sem[5]);
    
    
        return 0;
    }
    

    解法1

    利用信号量设置最多只能有4为哲学家同时拿左边筷子

    /***************************************
     * 哲学家吃饭
     * 解法1:设置信号量限制最多只有4人同时拿起左边筷子
     * ************************************/
    #include <stdio.h> 
    #include <pthread.h> 
    #include <unistd.h>
    #include <semaphore.h> 
    
    sem_t sem[6];
    
    void thread_1(void *arg)
    {
        int sum = 0;
        sem_wait(&sem[1]);
        printf("111拿起1筷子\n");
    
        sem_wait(&sem[0]);             //防止5人同时那左边筷子
        sem_wait(&sem[2]);
        printf("111拿起2筷子\n");
        printf("\n哲学家1吃完!\n");
        sem_post(&sem[1]);
        printf("111释放1筷子\n");
    
        sem_post(&sem[0]);
        sem_post(&sem[2]);
        printf("111释放2筷子\n");
    }
    
    void thread_2(void *arg)
    {
        sem_wait(&sem[2]);
        printf("222拿起2筷子\n");
    
        sem_wait(&sem[0]);             //防止5人同时那左边筷子
        sem_wait(&sem[3]);
        printf("222拿起3筷子\n");
        printf("\n哲学家2吃完!\n");
        sem_post(&sem[2]);
        printf("222释放2筷子\n");
    
        sem_post(&sem[0]);
        sem_post(&sem[3]);
        printf("222释放3筷子\n");
    }
    
    void thread_3(void *arg)
    {
        sem_wait(&sem[3]);
        printf("333拿起3筷子\n");
    
        sem_wait(&sem[0]);             //防止5人同时那左边筷子
        sem_wait(&sem[4]);
        printf("333拿起4筷子\n");
        printf("\n哲学家3吃完!\n");
        sem_post(&sem[3]);
        printf("333释放3筷子\n");
    
        sem_post(&sem[0]);
        sem_post(&sem[4]);
        printf("333释放4筷子\n");
    }
    
    void thread_4(void *arg)
    {
        //printf("*");
        sem_wait(&sem[4]);
        printf("444拿起4筷子\n");
    
        sem_wait(&sem[0]);             //防止5人同时那左边筷子
        //printf("A");
        sem_wait(&sem[5]);
        printf("444拿起5筷子\n");
        printf("\n哲学家4吃完!\n");
        sem_post(&sem[4]);
        printf("444释放4筷子\n");
    
        sem_post(&sem[0]);
        sem_post(&sem[5]);
        printf("444释放5筷子\n");
    }
    
    void thread_5(void *arg)
    {
        //printf("**");
        sem_wait(&sem[5]);
        printf("555拿起5筷子\n");
    
        sem_wait(&sem[0]);             //防止5人同时那左边筷子
        //printf("AA");
        sem_wait(&sem[1]);
        printf("555拿起1筷子\n");
        printf("\n哲学家5吃完!\n");
        sem_post(&sem[5]);
        printf("555释放5筷子\n");
    
        sem_post(&sem[0]);
        sem_post(&sem[1]);
        printf("555释放1筷子\n");
    }
    
    int main()
    {
        pthread_t thread1;
        pthread_t thread2;
        pthread_t thread3;
        pthread_t thread4;
        pthread_t thread5;
    
        sem_init(&sem[0], 0, 4);              //信号量设置为4,表示只能最多4个人拿左边的筷子
        sem_init(&sem[1], 0, 1);              //信号量设置为1,表示一次只能一个人拿该筷子
        sem_init(&sem[2], 0, 1);              //信号量设置为1,表示一次只能一个人拿该筷子
        sem_init(&sem[3], 0, 1);              //信号量设置为1,表示一次只能一个人拿该筷子
        sem_init(&sem[4], 0, 1);              //信号量设置为1,表示一次只能一个人拿该筷子
        sem_init(&sem[5], 0, 1);              //信号量设置为1,表示一次只能一个人拿该筷子
    
        int ret;
    
        //printf("%d\n%d\n%d\n%d\n%d\n",sem[1],sem[2],sem[3],sem[4],sem[5]);
    
        ret = pthread_create(&thread1, NULL, (void *)thread_1, NULL);
        if(ret != 0)
        {
            printf("Thread_1 wrong!\n");
        }
    
        ret = pthread_create(&thread2, NULL, (void *)thread_2, NULL);
        if(ret != 0)
        {
            printf("Thread_2 wrong!\n");
        }
    
        ret = pthread_create(&thread3, NULL, (void *)thread_3, NULL);
        if(ret != 0)
        {
            printf("Thread_3 wrong!\n");
        }
    
        ret = pthread_create(&thread4, NULL, (void *)thread_4, NULL);
        if(ret != 0)
        {
            printf("Thread_4 wrong!\n");
        }
    
        ret = pthread_create(&thread5, NULL, (void *)thread_5, NULL);
        if(ret != 0)
        {
            printf("Thread_5 wrong!\n");
        }
    
        pthread_join(thread1, NULL);
        pthread_join(thread2, NULL);
        pthread_join(thread3, NULL);
        pthread_join(thread4, NULL);
        pthread_join(thread5, NULL);
    
        sem_destroy(&sem[0]);
        sem_destroy(&sem[1]);
        sem_destroy(&sem[2]);
        sem_destroy(&sem[3]);
        sem_destroy(&sem[4]);
        sem_destroy(&sem[5]);
    
    
        return 0;
    }
    

    解法2

    对哲学家编号,奇数先拿左边偶数先那右边

    /***************************************
     * 哲学家吃饭
     * 解法2:奇数先拿左边,偶数先那右边
     * ************************************/
    #include <stdio.h> 
    #include <pthread.h> 
    #include <unistd.h>
    #include <semaphore.h> 
    
    sem_t sem[6];
    
    void thread_1(void *arg)
    {
        int sum = 0;
        sem_wait(&sem[1]);
        printf("111拿起1筷子\n");
        sem_wait(&sem[2]);
        printf("111拿起2筷子\n");
        printf("\n哲学家1吃完!\n");
        sem_post(&sem[1]);
        printf("111释放1筷子\n");
        sem_post(&sem[2]);
        printf("111释放2筷子\n");
    }
    
    void thread_2(void *arg)
    {
        sem_wait(&sem[3]);
        printf("222拿起3筷子\n");
        sem_wait(&sem[2]);
        printf("222拿起2筷子\n");
        printf("\n哲学家2吃完!\n");
        sem_post(&sem[3]);
        printf("222释放3筷子\n");
        sem_post(&sem[2]);
        printf("222释放2筷子\n");
    }
    
    void thread_3(void *arg)
    {
        sem_wait(&sem[3]);
        printf("333拿起3筷子\n");
        sem_wait(&sem[4]);
        printf("333拿起4筷子\n");
        printf("\n哲学家3吃完!\n");
        sem_post(&sem[3]);
        printf("333释放3筷子\n");
        sem_post(&sem[4]);
        printf("333释放4筷子\n");
    }
    
    void thread_4(void *arg)
    {
        //printf("*");
        sem_wait(&sem[5]);
        printf("444拿起5筷子\n");
        sem_wait(&sem[4]);
        printf("444拿起4筷子\n");
        //printf("A");
        printf("\n哲学家4吃完!\n");
        sem_post(&sem[5]);
        printf("444释放5筷子\n");
        sem_post(&sem[4]);
        printf("444释放4筷子\n");
    }
    
    void thread_5(void *arg)
    {
        //printf("**");
        sem_wait(&sem[5]);
        printf("555拿起5筷子\n");
        //printf("AA");
        sem_wait(&sem[1]);
        printf("555拿起1筷子\n");
        printf("\n哲学家5吃完!\n");
        sem_post(&sem[5]);
        printf("555释放5筷子\n");
        sem_post(&sem[1]);
        printf("555释放1筷子\n");
    }
    
    int main()
    {
        pthread_t thread1;
        pthread_t thread2;
        pthread_t thread3;
        pthread_t thread4;
        pthread_t thread5;
    
        sem_init(&sem[1], 0, 1);              //信号量设置为1,表示一次只能一个人拿该筷子
        sem_init(&sem[2], 0, 1);              //信号量设置为1,表示一次只能一个人拿该筷子
        sem_init(&sem[3], 0, 1);              //信号量设置为1,表示一次只能一个人拿该筷子
        sem_init(&sem[4], 0, 1);              //信号量设置为1,表示一次只能一个人拿该筷子
        sem_init(&sem[5], 0, 1);              //信号量设置为1,表示一次只能一个人拿该筷子
    
        int ret;
    
        //printf("%d\n%d\n%d\n%d\n%d\n",sem[1],sem[2],sem[3],sem[4],sem[5]);
    
        ret = pthread_create(&thread1, NULL, (void *)thread_1, NULL);
        if(ret != 0)
        {
            printf("Thread_1 wrong!\n");
        }
    
        ret = pthread_create(&thread2, NULL, (void *)thread_2, NULL);
        if(ret != 0)
        {
            printf("Thread_2 wrong!\n");
        }
    
        ret = pthread_create(&thread3, NULL, (void *)thread_3, NULL);
        if(ret != 0)
        {
            printf("Thread_3 wrong!\n");
        }
    
        ret = pthread_create(&thread4, NULL, (void *)thread_4, NULL);
        if(ret != 0)
        {
            printf("Thread_4 wrong!\n");
        }
    
        ret = pthread_create(&thread5, NULL, (void *)thread_5, NULL);
        if(ret != 0)
        {
            printf("Thread_5 wrong!\n");
        }
    
        pthread_join(thread1, NULL);
        pthread_join(thread2, NULL);
        pthread_join(thread3, NULL);
        pthread_join(thread4, NULL);
        pthread_join(thread5, NULL);
    
        sem_destroy(&sem[1]);
        sem_destroy(&sem[2]);
        sem_destroy(&sem[3]);
        sem_destroy(&sem[4]);
        sem_destroy(&sem[5]);
    
    
        return 0;
    }
    
    展开全文
  • 哲学家吃饭问题 c++编程 操作系统 实例
  • 用C语言实现了经典的哲学家吃饭问题, 资源中包含Makefile和源代码。
  • 多线程同步——哲学家吃饭问题

    千次阅读 2018-06-05 17:39:28
    最近在学习多线程编程(WIN32API下和C++11标准),学习过程中想起了在学操作系统的时候出现过的“哲学家吃饭问题”,当时听得云里雾里的,理解并不算透彻。恰好最近在学习多线程同步的知识,恰好可以利用最近所学...

    最近在进行多线程编程的学习,学习过程中想起了复习操作系统的时候见过的“哲学家吃饭问题”。当时理解并不算透彻。于是就趁这个机会,利用最近所学模拟一下这个过程吧。

    一、问题描述

    二、问题分析

    哲学家就餐问题需要协调考虑两个问题:

    1、不能让哲学家饿死(避免死锁);

    2、要尽量提升吃饭的效率,也就是同一时间尽量让多一些哲学家吃饭(最多同时两个)。

    我们考虑这两个问题,然后设计我们的策略。

    我们可以考虑用五个互斥量来表示五把叉子,用五个整型来表示“盘子里剩下的面条还有多少”。

    1、可能会导致死锁的一种最糟糕策略

    某个哲学家的吃面步骤如下:

    //while(true)
    //{
    //    思考;
    //    给左边叉子上锁;//去拿左边叉子
    //    给右边叉子上锁;//去拿右边叉子
    //    吃面条;
    //    给左边叉子解锁;//去拿左边叉子
    //    给右边叉子解锁;//去拿右边叉子
    //}

    对于上面的代码,让我们考虑一种情况:如果某一时刻,所有哲学家都拿了自己左边的叉子,接下来他们都要去拿右边的叉子。此时,他们都会发现右边已经没有叉子了。但他们只有在吃完面条后才会放下自己左手的叉子,于是他们每个人左手拿着叉子面面相觑,都不愿意让出自己的叉子,陷入了死锁。因此,解决哲学家吃饭问题的关键点在于,如何避免死锁的发生。

    如果每次只允许一个哲学家吃饭,那就可以确保不产生死锁。但理论上可以允许两个不相邻的哲学家同时吃面条,因此这种策略造成了叉子资源的浪费。

    2、解决哲学家吃饭问题的一种思路

    要解决哲学家就餐的问题,有一个基本的指导思想:放下叉子的时候,可以先放左边再放右边。但拿叉子的时候,要么不拿(缺了左边或右边的叉子),要么一次拿两把叉子!

    问题来了,策略看起来很简单,但程序实现的关键点在于,如何模拟“同时拿起左右两把叉子,但凡少一个就不拿”?

    (1)用五个互斥量模拟五把叉子

    利用C++11中mutex类的try_lock成员函数。每个哲学家想要吃面条时,首先尝试拿起左手的叉子。如果能拿到,再尝试拿起右手的叉子。如果能拿到两把叉子,就吃面,吃完后释放两把叉子。如果无法拿到右的叉子,就释放左边的叉子。假设一盘面条的数量为50,每个哲学家每次吃掉1020的面条(随机),代码如下:

    #include<iostream>
    #include<thread>
    #include<mutex>
    #include<ctime>
    
    using namespace std;
    using namespace std::this_thread;
    using namespace std::chrono;
    
    //用五个互斥量表示五支叉子
    mutex fork[5];
    
    //用一个规模为5的整型数组来表示每个盘子剩余的面条
    int nuddles[5] = { 50,50,50,50,50 };
    
    //吃面条函数
    void eat(int id) {
    	//id为哲学家编号
    	while (true) {
    		//尝试同时拿起左手边和右手边的叉子
    		if (fork[id].try_lock()) {
    			//先尝试拿起左手边的叉子
    			//如果能拿起左手边的叉子,再拿右手边的
    			if (fork[(id + 1) % 5].try_lock()) {
    				//如果也能拿起右手边的叉子,吃面条
    				//开吃,每次吃掉的面条数量为10-20之间的一个数字
    				printf("哲学家%d开始吃面条!\n", id + 1);
    				srand((unsigned)time(NULL));
    				int numbereated = rand() % (20 - 10 + 1) + 10;
    				sleep_for(seconds(numbereated % 10));//吃一段时间
    				nuddles[id] -= numbereated;
    				if (nuddles[id] <= 0) {
    					printf("                          哲学家%d吃完了他的所有面条!\n", id+1);
    					fork[id].unlock();
    					fork[(id + 1) % 5].unlock();
    					break;
    				}
    				printf("哲学家%d吃完,面条剩余%d!\n", id+1, nuddles[id]);
    				fork[id].unlock();
    				fork[(id + 1) % 5].unlock();
    				sleep_for(milliseconds(200));//吃完之后歇一会,让其它哲学家能够吃上
    			}
    			else {
    				//如果没办法拿起右手边的叉子,记得要把左手边的叉子放下来
    				fork[id].unlock();
    				sleep_for(milliseconds(100));//歇一会(思考),让其它哲学家能够吃上
    			}
    		}
    	}
    }
    
    int main()
    {
    	printf("开始吃饭!每人拥有50面条\n");
    	thread t1(eat, 0);
    	thread t2(eat, 1);
    	thread t3(eat, 2);
    	thread t4(eat, 3);
    	thread t5(eat, 4);
    	t1.join(); t2.join(); t3.join(); t4.join(); t5.join();
    	printf("所有哲学家吃完!\n");
    	return 0;
    }
    

    程序运行结果如下


    上面的代码乍看起来是没问题的,但存在隐患。我们考虑一下,如果某一时刻,所有哲学家都拿了自己左边的叉子,接下来他们都要去拿右边的叉子。当这种情况发生时,他们都会发现右边已经没有叉子了。于是他们都把自己左边的叉子放回桌子。然后他们又发现左边有叉子,再拿起来,然后右边还是没有叉子,于是又放下,循环往复,还是陷入了死锁。这种情况虽然比较难遇到,但也不是不可能的。毕竟上面代码并没有遵循“当且仅当自己左边和右边的叉子都在的时候,才同时拿起两把叉子”这个原则。

    (2)用临界区来实现“同时拿叉子”

    要实现“同时拿两把叉子”这个操作,可以把“拿叉子”动作设为临界区。

    #include<process.h>
    #include<Windows.h>
    #include<iostream>
    #include<ctime>
    
    using namespace std;
    
    //用五个bool型变量表示五把叉子
    //true表示可以拿,false表示已经被拿走
    bool fork[5] = { true,true,true,true,true };
    
    //用一个规模为5的整型数组来表示每个盘子剩余的面条
    int nuddles[5] = { 50,50,50,50,50 };
    
    //定义临界区结构为全局变量
    CRITICAL_SECTION Section;
    
    //拿叉子
    bool takeForks(int id) {
    	//进入临界区,确保每个时刻只有一个哲学家在拿叉子
    	EnterCriticalSection(&Section);
    	bool leftfork = fork[id], rightfork = fork[(id + 1) % 5];
    	if (leftfork && rightfork) {
    		//同时拿起
    		fork[id] = false;
    		fork[(id + 1) % 5] = false;
    	}
    	LeaveCriticalSection(&Section);
    	return leftfork && rightfork;
    }
    
    //吃面条函数
    void eat(void *param) {
    	int id = *(int*)param;
    	while (true) {
    		if (takeForks(id)) {
    			printf("哲学家%d开始吃面条!\n", id + 1);
    			srand((unsigned)time(NULL));
    			int numbereated = rand() % (20 - 10 + 1) + 10;
    			//Sleep((numbereated%10)*1000);
    			nuddles[id] -= numbereated;
    			if (nuddles[id] <= 0) {
    				printf("                          哲学家%d吃完了他的所有面条!\n", id + 1);
    				//EnterCriticalSection(&Section);
    				fork[id] = true;
    				fork[(id + 1) % 5] = true;
    				//LeaveCriticalSection(&Section);
    				break;
    			}
    			printf("哲学家%d吃完,面条剩余%d!\n", id + 1, nuddles[id]);
    			//EnterCriticalSection(&Section);
    			fork[id] = true;
    			fork[(id + 1) % 5] = true;
    			//LeaveCriticalSection(&Section);
    			Sleep(200);//思考
    		}
    	}
    }
    
    int main()
    {
    	//初始化临界区
    	InitializeCriticalSection(&Section);
    	printf("开始吃饭!每人拥有50面条\n");
    	int p[5] = { 0,1,2,3,4 };
    	uintptr_t t1 = _beginthread(eat, 0, (void*)p);
    	uintptr_t t2 = _beginthread(eat, 0, (void*)(p + 1));
    	uintptr_t t3 = _beginthread(eat, 0, (void*)(p + 2));
    	uintptr_t t4 = _beginthread(eat, 0, (void*)(p + 3));
    	uintptr_t t5 = _beginthread(eat, 0, (void*)(p + 4));
    	HANDLE hArr[] = { (HANDLE)t1,(HANDLE)t2, (HANDLE)t3, (HANDLE)t4, (HANDLE)t5 };
    	WaitForMultipleObjects(5, hArr, TRUE, INFINITE);
    	printf("所有哲学家吃完!\n");
    	return 0;
    }
    

    3、解决哲学家吃饭问题的另一种思路:按编号从小到大的顺序拿叉子

    作如下规定:每个哲学家不按照“先拿左边的叉子再拿右边的叉子”的顺序拿叉子,而是“先拿编号小的叉子,再拿编号大的叉子”。如果按照这个规则,对于题目给出的哲学家和叉子的编号,0到3号哲学家都会先拿左边再拿右边,但4号哲学家相反,是先拿右边再拿左边。这样就可以避免死锁的情况发生。

    //while(true)
    //{
    //    思考;
    //    给编号小的叉子上锁;
    //    给编号大的叉子上锁;
    //    吃面条;
    //    给编号小的叉子解锁;
    //    给编号大的叉子解锁;
    //}
    
    #include<iostream>
    #include<thread>
    #include<mutex>
    #include<ctime>
    
    using namespace std;
    using namespace std::this_thread;
    using namespace std::chrono;
    
    //用五个互斥量表示五支叉子
    mutex fork[5];
    
    //用一个规模为5的整型数组来表示每个盘子剩余的面条
    int nuddles[5] = { 50,50,50,50,50 };
    
    //吃面条函数
    void eat(int id) {
    	//id为哲学家编号
    	while (true) {
    		if (id < (id + 1) % 5) {
    			fork[id].lock();
    			fork[(id + 1) % 5].lock();
    			printf("哲学家%d开始吃面条!\n", id + 1);
    			srand((unsigned)time(NULL));
    			int numbereated = rand() % (20 - 10 + 1) + 10;
    			//sleep_for(seconds(numbereated % 10));//吃一段时间
    			nuddles[id] -= numbereated;
    			if (nuddles[id] <= 0) {
    				printf("                          哲学家%d吃完了他的所有面条!\n", id + 1);
    				fork[id].unlock();
    				fork[(id + 1) % 5].unlock();
    				break;
    			}
    			printf("哲学家%d吃完,面条剩余%d!\n", id + 1, nuddles[id]);
    			fork[id].unlock();
    			fork[(id + 1) % 5].unlock();
    			sleep_for(milliseconds(200));//吃完之后歇一会,让其它哲学家能够吃上
    		}
    		else {
    			fork[(id + 1) % 5].lock();
    			fork[id].lock();
    			printf("哲学家%d开始吃面条!\n", id + 1);
    			srand((unsigned)time(NULL));
    			int numbereated = rand() % (20 - 10 + 1) + 10;
    			//sleep_for(seconds(numbereated % 10));//吃一段时间
    			nuddles[id] -= numbereated;
    			if (nuddles[id] <= 0) {
    				printf("                          哲学家%d吃完了他的所有面条!\n", id + 1);
    				fork[(id + 1) % 5].unlock();
    				fork[id].unlock();
    				break;
    			}
    			printf("哲学家%d吃完,面条剩余%d!\n", id + 1, nuddles[id]);
    			fork[(id + 1) % 5].unlock();
    			fork[id].unlock();
    			sleep_for(milliseconds(200));//吃完之后歇一会(思考),让其它哲学家能够吃上
    		}
    		
    	}
    }
    
    int main()
    {
    	printf("开始吃饭!每人拥有50面条\n");
    	thread t1(eat, 0);
    	thread t2(eat, 1);
    	thread t3(eat, 2);
    	thread t4(eat, 3);
    	thread t5(eat, 4);
    	t1.join(); t2.join(); t3.join(); t4.join(); t5.join();
    	printf("所有哲学家吃完!\n");
    	return 0;
    }


    展开全文
  • ????哲学家吃饭问题 ????管程 学习资源来源: 王道考研 操作系统

    📖哲学家吃饭问题

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    📖管程

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    学习资源来源:
    王道考研 操作系统

    展开全文
  • 哲学家就餐问题-对线程死锁的理解 两个线程的死锁问题: 线程1 首先占有对象1,接着试图...史上著名哲学家吃饭问题: 一张圆桌上坐着5名哲学家,每两个哲学家之间的桌上摆一根筷子,桌子的中间是一碗米饭,如图...
  • 吃饭时,哲学家会先拿起左手的那根筷子,再去拿右手的那根。当一个哲学家拿到两根筷子时,就可以开始吃饭,吃着吃着,又会放下筷子开始思考。 以上描述的场景,就会出现死锁:在某一时刻,所有的哲学家同时拿起左手...
  • 文章目录线程的概念:概念:关系:区别:生产者消费者问题:问题描述:问题分析:代码展示:哲学家吃饭问题:问题描述:问题分析:问题解法一:问题解法二: 线程的概念: 概念: 进程:从操作系统核心角度来说,...
  • //五个哲学家围坐在一起,两人之间都放有一个叉子,意大利面需要2个叉子吃,哲学家吃饭时候叉子只能拿左右手,哲学家除了吃饭时间其他时间都在思考 #include <stdio.h> #include <stdlib.h> #include...
  • 用unix编程中的信号量函数实现的经典ipc问题哲学家吃饭
  • 3 哲学家吃饭问题 3.1 题面 哲学家吃饭问题是一个很有名的死锁模型,leetcode1226题提供了这道题。题面如下: 5 个沉默寡言的哲学家围坐在圆桌前,每人面前一盘意面。叉子放在哲学家之间的桌面上。(5 个哲学家,5 ...
  •  假设有5个哲学家,他们花费一生中的时光思考和吃饭。这些哲学家共用一个圆桌,每个哲学家都有一把椅子。在桌子中央是一碗通心面,在桌子上放着5只筷子。当一个哲学家思考时,他与其他同事不交互。时而,哲学家会...
  • 哲学家进餐问题描述有五个哲学家,他们的生活方式是交替地进行思考和进餐,哲学家们共用一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五支筷子,平时哲学家进行思考,饥饿时便试图取其左、右最靠近他的...
  • 有五个哲学家围成一圈,每人左右各有一只筷子,每人只能使用自己左右的筷子,当拿起左右筷子后就可以吃饭,否则就等待。
  • 一个简单的cpp文件,一种简单的实现方法,初学者可用于参考
  • 有五个哲学家公用一张餐桌,分别坐在周围的五张椅子上,在餐桌上有五个碗和五只筷子,他们的生活方式是交替地进行思考和用餐。平时,一个哲学家进行思考,饥饿时便试图拿取其左右最靠近他的筷子,只有在他拿到两只...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,746
精华内容 2,698
关键字:

哲学家吃饭问题