You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在哲学家就餐问题代码中触发死锁状态?

如何修改哲学家就餐问题代码以产生死锁

你的原代码采用了Dijkstra的防死锁解法,通过verifica函数全局检查左右邻居的就餐状态,确保只有当两边都没人吃饭时,当前哲学家才能拿起叉子,从根源上避免了“每人持一根叉子等待另一根”的死锁场景。要制造死锁,我们需要去掉这个全局协调逻辑,让每个哲学家独立地按固定顺序拿叉子,最终形成循环等待。

核心修改思路

把每个叉子设为独立的信号量,让所有哲学家都遵循先拿左侧叉子,再拿右侧叉子的顺序。当所有哲学家同时拿起左侧叉子后,都会卡在等待右侧叉子的状态——此时每个叉子都被一人持有,没人能释放手里的叉子,死锁就会产生。

修改后的完整代码

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

#define NUM_FIL 5
#define PENSA 2
#define AFFAMATO 1
#define MANGIA 0
#define SINISTRA (filosofi + 4) % NUM_FIL
#define DESTRA (filosofi + 1) % NUM_FIL

int stato[NUM_FIL];
int fil[NUM_FIL] = {0,1,2,3,4};

sem_t mutex;
sem_t forchette[NUM_FIL];  // 每个叉子对应一个信号量,初始值为1表示可用

void schermoIniziale();
void prendeForchetta(int filosofi);
void lasciaForchetta(int filosofi);
void* filosofo(void* num);

void prendeForchetta(int filosofi){
    sem_wait(&mutex);
    stato[filosofi] = AFFAMATO;
    printf("Filosofo %d e' affamato\n", filosofi + 1);
    sem_post(&mutex);

    // 固定顺序:先拿自己面前的叉子(左侧),再拿右侧邻居的叉子
    sem_wait(&forchette[filosofi]);
    printf("Filosofo %d prende la forchetta %d\n", filosofi + 1, filosofi + 1);
    
    sem_wait(&forchette[DESTRA]);
    printf("Filosofo %d prende la forchetta %d\n", filosofi + 1, DESTRA + 1);

    sem_wait(&mutex);
    stato[filosofi] = MANGIA;
    printf("Filosofo %d MANGIA\n", filosofi + 1);
    sem_post(&mutex);
    sleep(1);
}

void lasciaForchetta(int filosofi){
    sem_wait(&mutex);
    stato[filosofi] = PENSA;
    printf("Filosofo %d lascia le forchette %d e %d \n", filosofi + 1, filosofi + 1, DESTRA + 1);
    printf("Filosofo %d PENSA\n", filosofi + 1);
    sem_post(&mutex);

    // 释放叉子,顺序不影响死锁产生,只需和拿起顺序对应
    sem_post(&forchette[filosofi]);
    sem_post(&forchette[DESTRA]);
    sleep(1);
}

void* filosofo(void* num){
    while (true) {
        int* i = num;
        sleep(1);
        prendeForchetta(*i);
        sleep(1);
        lasciaForchetta(*i);
    }
}

int main(){
    int i;
    pthread_t fil_id[NUM_FIL];
    sem_init(&mutex, 0, 1);
    schermoIniziale();
    sleep(2);

    // 初始化每个叉子信号量,初始值为1(可用状态)
    for (i = 0; i < NUM_FIL; i++){
        sem_init(&forchette[i], 0, 1);
    }

    for (i = 0; i < NUM_FIL; i++) {
        pthread_create(&fil_id[i], NULL, filosofo, &fil[i]);
        printf("Filosofo %d PENSA\n", i + 1);
    }

    for (i = 0; i < NUM_FIL; i++){
        pthread_join(fil_id[i], NULL);
    }
}

void schermoIniziale(){
    printf("+-----------BENVENUTO------------+\n");
    printf("|   Dining philosophers problem  |\n");
    printf("+--------------------------------+\n\n");
}

死锁产生过程说明

程序运行后,所有哲学家会在思考结束后尝试拿起左侧叉子。由于操作系统的调度特性,很容易出现所有哲学家都成功拿起左侧叉子的情况:此时每个叉子都被一个哲学家持有,而每个哲学家都在等待右侧邻居手里的叉子。没有任何哲学家能继续执行(拿不到第二根叉子就无法吃饭),也不会有人释放手里的叉子(只有吃完才会释放),最终形成循环等待,触发死锁。

内容的提问来源于stack exchange,提问作者Francesco Nardiello

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 19:14:59