调用pthread_create触发段错误:Dining Philosophers问题模拟代码故障
解决 Dining Philosophers 问题中的线程同步与死锁问题
看起来你在实现经典的 Dining Philosophers 问题时遇到了麻烦,我先帮你梳理这段代码常见的漏洞,再给出完整的可运行修正实现。
原代码的核心问题
你给出的代码只定义了基础的同步变量和不完整的test函数,缺少了哲学家拿/放叉子的核心逻辑、线程入口函数,也没有处理同步原语的初始化/销毁,这些缺失很容易导致死锁、线程状态异常等问题。
完整修正后的代码
#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> // 创建互斥锁、条件变量及状态变量 pthread_mutex_t mutex; pthread_cond_t cond_var[5]; enum { THINKING, HUNGRY, EATING } state[5]; // 测试是否可获取叉子(核心判断逻辑) void test(int pNumber) { // 仅当自己饥饿,且左右邻居都不在吃饭时,才能拿起叉子 if (state[pNumber] == HUNGRY && state[(pNumber + 4) % 5] != EATING && state[(pNumber + 1) % 5] != EATING) { state[pNumber] = EATING; // 唤醒当前等待的哲学家(不用再等了,可以吃饭) pthread_cond_signal(&cond_var[pNumber]); } } // 拿起叉子的操作 void pickup(int pNumber) { pthread_mutex_lock(&mutex); state[pNumber] = HUNGRY; printf("哲学家 %d 感到饥饿,尝试拿叉子\n", pNumber); // 先检查是否能直接拿到叉子 test(pNumber); // 如果没拿到,就进入条件等待(等待时会自动释放互斥锁,被唤醒后重新获取锁) while (state[pNumber] != EATING) { pthread_cond_wait(&cond_var[pNumber], &mutex); } pthread_mutex_unlock(&mutex); } // 放下叉子的操作 void putdown(int pNumber) { pthread_mutex_lock(&mutex); state[pNumber] = THINKING; printf("哲学家 %d 吃完了,放下叉子\n", pNumber); // 通知左右邻居:我吃完了,你们可以试试拿叉子了 test((pNumber + 4) % 5); test((pNumber + 1) % 5); pthread_mutex_unlock(&mutex); } // 哲学家的线程主体(循环:思考→饥饿→吃饭) void* philosopher(void* arg) { int pNumber = *(int*)arg; free(arg); // 释放传入的参数内存 while (1) { // 思考阶段(随机时长模拟) printf("哲学家 %d 正在思考\n", pNumber); sleep(rand() % 3); // 尝试拿叉子吃饭 pickup(pNumber); printf("哲学家 %d 开始吃饭\n", pNumber); sleep(rand() % 2); // 吃完放下叉子 putdown(pNumber); } return NULL; } int main() { pthread_t threads[5]; int i; // 初始化互斥锁和所有条件变量 pthread_mutex_init(&mutex, NULL); for (i = 0; i < 5; i++) { pthread_cond_init(&cond_var[i], NULL); state[i] = THINKING; // 初始状态都是思考 } // 创建5个哲学家线程 for (i = 0; i < 5; i++) { int* pNumber = malloc(sizeof(int)); *pNumber = i; pthread_create(&threads[i], NULL, philosopher, pNumber); } // 等待所有线程(程序会一直运行,除非手动终止) for (i = 0; i < 5; i++) { pthread_join(threads[i], NULL); } // 销毁同步原语(实际这里不会执行到,因为线程是无限循环) pthread_mutex_destroy(&mutex); for (i = 0; i < 5; i++) { pthread_cond_destroy(&cond_var[i]); } return 0; }
关键逻辑说明
test函数:这是避免死锁的核心——它确保只有当哲学家的左右邻居都不在吃饭时,才允许当前哲学家拿起叉子,彻底杜绝了所有哲学家同时拿左叉子导致的死锁场景。pickup/putdown函数:通过互斥锁保护共享的state数组,确保状态修改的原子性;putdown后主动通知邻居检查状态,避免线程无限等待。- 线程主体:用随机睡眠模拟思考和吃饭的时长,更贴近真实场景的并发行为。
内容的提问来源于stack exchange,提问作者N Sharrett
相关产品推荐
相关产品推荐

