1226-哲学家进餐

1226-哲学家进餐,第1张

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++封装好的线程库。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/4749295.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-08
下一篇 2022-11-08

发表评论

登录后才能评论

评论列表(0条)

保存