MST

星途 面试题库

面试题:并发与同步之信号量解决哲学家进餐问题

在哲学家进餐问题中,假设有5个哲学家,使用信号量机制来避免死锁,描述你的实现思路,并写出关键代码片段。
40.0万 热度难度
操作系统并发与同步

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 资源分配:为每个哲学家分配一个信号量,用于表示他们是否可以拿起筷子。同时,定义一个互斥信号量,用于保护共享资源(如筷子的状态)的访问。
  2. 哲学家行为:每个哲学家在尝试拿起筷子之前,先获取互斥信号量,以确保对筷子状态的修改是安全的。然后检查相邻的筷子是否可用(通过获取相应的信号量),如果都可用则拿起筷子开始进餐,否则释放互斥信号量并等待。
  3. 避免死锁:通过合理的资源分配策略,例如按照某种顺序获取筷子(如按照哲学家编号从小到大),或者限制同时进餐的哲学家数量,来避免死锁的发生。

关键代码片段(以C语言和POSIX信号量为例)

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>

#define N 5 // 哲学家数量
sem_t mutex; // 互斥信号量
sem_t chopstick[N]; // 筷子信号量数组

void *philosopher(void *num) {
    int i = *(int *)num;
    while (1) {
        printf("哲学家 %d 正在思考\n", i);
        // 获取互斥信号量
        sem_wait(&mutex);
        // 尝试获取相邻的两根筷子
        sem_wait(&chopstick[i]);
        sem_wait(&chopstick[(i + 1) % N]);
        // 释放互斥信号量
        sem_post(&mutex);

        printf("哲学家 %d 正在进餐\n", i);

        // 放下筷子
        sem_post(&chopstick[i]);
        sem_post(&chopstick[(i + 1) % N]);
    }
    return NULL;
}

int main() {
    pthread_t tid[N];
    int i, id[N];

    // 初始化互斥信号量
    sem_init(&mutex, 0, 1);
    // 初始化筷子信号量
    for (i = 0; i < N; i++) {
        sem_init(&chopstick[i], 0, 1);
    }

    // 创建哲学家线程
    for (i = 0; i < N; i++) {
        id[i] = i;
        pthread_create(&tid[i], NULL, philosopher, &id[i]);
    }

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

    // 销毁信号量
    sem_destroy(&mutex);
    for (i = 0; i < N; i++) {
        sem_destroy(&chopstick[i]);
    }

    return 0;
}