栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

1226-哲学家进餐

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

1226-哲学家进餐

问题描述

https://leetcode-cn.com/problems/the-dining-philosophers/

求解思路

题目没有提供C语言解决方案,只能采用C++,C++有一套自己封装了POSIX的线程库,然而我并不会用,只能还是调用底层的sem_t互斥量及其相关操作集来实现线程同步(又逮到一个C with class)

对于哲学家进餐问题,一共有三种方式避免死锁:

  1. 保证每个哲学家拿叉子互斥,即对哲学家拿起左右两只叉子这个过程上锁保护
  2. 令奇数号哲学家先拿左手边的叉子,偶数号的哲学家先拿右手边的叉子
  3. 至多允许4名哲学家同时吃饭
代码实现

死锁避免方式1:利用mutex保证哲学家同时拿左右两只叉子

#include 
class DiningPhilosophers {
   public:
    DiningPhilosophers() {
        for (int i = 0; i < 5; ++i) {
            sem_init(&forks[i], 0, 1);
        }
        sem_init(&mutex, 0, 1);
    }
    ~DiningPhilosophers() {
        for (int i = 0; i < 5; ++i) {
            sem_destroy(&forks[i]);
        }
        sem_destroy(&mutex);
    }

    void wantsToEat(int philosopher,
                    function pickLeftFork,
                    function pickRightFork,
                    function eat,
                    function putLeftFork,
                    function putRightFork) {
        int leftFork = philosopher;
        int rightFork = (philosopher + 1) % 5;
        sem_wait(&mutex);
        sem_wait(&forks[leftFork]);
        sem_wait(&forks[rightFork]);
        sem_post(&mutex);

        pickLeftFork();
        pickRightFork();

        eat();

        putLeftFork();
        putRightFork();
        sem_post(&forks[leftFork]);
        sem_post(&forks[rightFork]);
    }

   private:
    sem_t forks[5];
    sem_t mutex;
}

死锁避免方式2:奇数号哲学家先拿左手边的叉子,偶数号的哲学家先拿右手边的叉子

#include 

class DiningPhilosophers {
   public:
    DiningPhilosophers() {
        for (int i = 0; i < 5; ++i) {
            sem_init(&forks[i], 0, 1);
        }
    }
    ~DiningPhilosophers() {
        for (int i = 0; i < 5; ++i) {
            sem_destroy(&forks[i]);
        }
    }

    void wantsToEat(int philosopher,
                    function pickLeftFork,
                    function pickRightFork,
                    function eat,
                    function putLeftFork,
                    function putRightFork) {
        int leftFork = philosopher;
        int rightFork = (philosopher + 1) % 5;
        if ((philosopher & 1) == 1) {
            sem_wait(&forks[leftFork]);
            sem_wait(&forks[rightFork]);
            pickLeftFork();
            pickRightFork();
        } else {
            sem_wait(&forks[rightFork]);
            sem_wait(&forks[leftFork]);
            pickRightFork();
            pickLeftFork();
        }

        eat();

        putLeftFork();
        putRightFork();
        sem_post(&forks[leftFork]);
        sem_post(&forks[rightFork]);
    }

   private:
    sem_t forks[5];
};

死锁避免方式3:最多允许4个哲学家同时进餐

#include 

class DiningPhilosophers {
   public:
    DiningPhilosophers() {
        for (int i = 0; i < 5; ++i) {
            sem_init(&forks[i], 0, 1);
        }
        sem_init(&nums, 0, 4);
    }
    ~DiningPhilosophers() {
        for (int i = 0; i < 5; ++i) {
            sem_destroy(&forks[i]);
        }
        sem_destroy(&nums);
    }

    void wantsToEat(int philosopher,
                    function pickLeftFork,
                    function pickRightFork,
                    function eat,
                    function putLeftFork,
                    function putRightFork) {
        int leftFork = philosopher;
        int rightFork = (philosopher + 1) % 5;
        sem_wait(&nums);

        sem_wait(&forks[leftFork]);
        sem_wait(&forks[rightFork]);
        pickLeftFork();
        pickRightFork();

        eat();

        putLeftFork();
        putRightFork();
        sem_post(&forks[leftFork]);
        sem_post(&forks[rightFork]);

        sem_post(&nums);
    }

   private:
    sem_t forks[5];
    sem_t nums;
};
收获和疑惑

C++提供了比函数指针更高级的函数作为参数传递的方式:借助function关键字,有时间深入学习。

有时间学习一下C++封装好的线程库。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/346699.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号