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

如何修改C语言实现的哲学家进餐问题代码以避免死锁?

解决哲学家进餐问题的死锁问题

你的代码出现死锁的核心原因是所有哲学家都遵循“先拿左叉子、再拿右叉子”的顺序,当所有哲学家同时拿起左侧叉子后,都会等待右侧叉子释放,形成循环等待,触发死锁。

下面提供两种简单有效的修改方案:

方案一:调整最后一位哲学家的拿叉子顺序

让编号为SIZE-1的哲学家先拿右侧叉子,再拿左侧叉子,打破循环等待的条件,从根本上避免死锁。修改后的代码如下:

void *
philosopher (void * _args)
{
  struct args *args = (struct args *) _args;
  int self = args->self;
  int next = (self + 1) % SIZE;

  // 最后一位哲学家反向拿叉子
  if (self == SIZE - 1) {
    sem_wait(args->sems[next]);   // 先拿右侧叉子
    sem_wait(args->sems[self]);   // 再拿左侧叉子
  } else {
    sem_wait(args->sems[self]);   // 其他人先拿左侧叉子
    sem_wait(args->sems[next]);   // 再拿右侧叉子
  }

  /* 临界区(进餐) */
  printf("哲学家%d正在进餐\n", self);
  // 模拟进餐时间,可根据需要调整
  sleep(1);

  // 按拿叉子的反向顺序放下
  if (self == SIZE - 1) {
    sem_post(args->sems[self]);
    sem_post(args->sems[next]);
  } else {
    sem_post(args->sems[next]);
    sem_post(args->sems[self]);
  }

  /* 执行其他任务并退出线程 */
  return NULL;
}

方案二:限制同时拿叉子的哲学家数量

设置一个额外的信号量,限制最多SIZE-1个哲学家进入拿叉子的流程,确保至少有一个哲学家能拿到两把叉子并完成进餐,释放资源。修改示例:

首先在结构体中添加一个共享的信号量:

struct args {
  int self;
  sem_t *sems;
  sem_t *max_philosophers; // 新增限制信号量,初始值设为 SIZE-1
};

然后修改哲学家线程函数:

void *
philosopher (void * _args)
{
  struct args *args = (struct args *) _args;
  int self = args->self;
  int next = (self + 1) % SIZE;

  // 先申请进入拿叉子的权限
  sem_wait(args->max_philosophers);

  sem_wait(args->sems[self]);   // 拿左侧叉子
  sem_wait(args->sems[next]);   // 拿右侧叉子

  /* 临界区(进餐) */
  printf("哲学家%d正在进餐\n", self);
  sleep(1);

  sem_post(args->sems[next]);   // 放下右侧叉子
  sem_post(args->sems[self]);   // 放下左侧叉子

  // 释放进入权限,让其他哲学家可以尝试拿叉子
  sem_post(args->max_philosophers);

  /* 执行其他任务并退出线程 */
  return NULL;
}

这两种方案都能有效避免死锁,方案一实现更简洁,不需要额外信号量;方案二逻辑更直观,适合理解死锁的资源竞争本质。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 20:01:21