📜  门|门 CS 1996 |问题 22(1)

📅  最后修改于: 2023-12-03 14:58:34.862000             🧑  作者: Mango

门|门 CS 1996 |问题 22

简介

这是一道经典的计算机科学问题,也被称为“哲学家就餐问题”。问题场景为五个哲学家围坐在一张圆桌周围,每个哲学家面前摆放着一只碗和一支叉子。哲学家只能进行两种活动:思考和就餐。当哲学家决定就餐时,需要先从他左右两侧各拿一支叉子,然后就餐,再放下叉子,才能重新开始思考。

问题的核心在于如何避免死锁。当每个哲学家同时拿起自己左边的叉子时,就会形成死锁,因为每个哲学家都在等待右边的叉子,而此时另一名哲学家却拿走了他需要的叉子,导致所有哲学家都无法进行下去。

解决方案

有多种解决方案,其中比较经典的是使用互斥锁和条件变量。基本思路是每个哲学家需要先获取到左右两侧的叉子才能开始就餐,在此过程中需要保证每根叉子只能被一个哲学家使用。此外,还需要考虑如何让一个哲学家获得叉子时,另一个哲学家不会同时竞争同一根叉子。

下面是一种简单的解决方案:

#include <pthread.h>

#define N 5   // 哲学家数量
pthread_mutex_t forks[N];   // 叉子锁
pthread_cond_t cond[N];     // 条件变量,记录每个哲学家的状态

void *dine(void *arg) {
    int index = *(int *)arg;
    int left = index;
    int right = (index + 1) % N;

    for (;;) {
        // 思考
        printf("philosopher %d is thinking\n", index);
        sleep(rand() % 5);

        // 获取左侧的叉子
        pthread_mutex_lock(&forks[left]);
        while (pthread_mutex_trylock(&forks[right]) != 0) {
            pthread_cond_wait(&cond[index], &forks[left]);   // 等待右侧的叉子
        }

        // 获取右侧的叉子
        printf("philosopher %d is eating\n", index);
        sleep(rand() % 5);
        pthread_mutex_unlock(&forks[right]);

        // 释放叉子
        pthread_mutex_unlock(&forks[left]);

        // 通知右侧的哲学家可以拿起叉子
        pthread_cond_signal(&cond[(index + 1) % N]);
    }
}

int main() {
    pthread_t tid[N];
    int index[N];

    // 初始化叉子锁和条件变量
    for (int i = 0; i < N; ++i) {
        pthread_mutex_init(&forks[i], NULL);
        pthread_cond_init(&cond[i], NULL);
    }

    // 创建线程
    for (int i = 0; i < N; ++i) {
        index[i] = i;
        pthread_create(&tid[i], NULL, dine, (void *)&index[i]);
    }

    // 等待线程结束
    for (int i = 0; i < N; ++i) {
        pthread_join(tid[i], NULL);
    }

    // 销毁叉子锁和条件变量
    for (int i = 0; i < N; ++i) {
        pthread_mutex_destroy(&forks[i]);
        pthread_cond_destroy(&cond[i]);
    }

    return 0;
}
注意事项
  • 使用条件变量时需要确保唤醒的线程处于等待状态。
  • 使用互斥锁时需要注意加锁和解锁的顺序,以避免死锁。
  • 叉子锁和条件变量可以优化,例如使用数组代替单独的变量,以减少代码量和线程数。
  • 此方案只是其中一种,不同的场景和需求可能需要不同的解决方案。