如何修改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
相关产品推荐
相关产品推荐

