使用POSIX线程实现哲学家就餐问题时id取值异常求助
代码错误分析
你遇到的id取值异常、输出错误是以下几个明确的bug导致的:
1. 致命的线程参数悬垂指针问题
createThread函数的number是函数栈上的局部变量,函数返回后该内存空间会被立即回收复用。你调用pthread_create时传入了&number,后续线程执行philFunc解引用这个地址时,读到的已经是被销毁的垃圾值,这是id取值过大、输出异常的核心原因。
2. 左叉子下标越界错误
philFunc中leftSpoon的赋值逻辑错误:当id为0时,左叉子应该是最后一个下标PHILOSOPHERS - 1,你的代码写的是PHILOSOPHERS,会直接访问互斥锁数组越界,触发未定义行为。
3. 随机数种子初始化错误
所有线程几乎同时调用srand(time(0)),time返回的是秒级时间戳,所有线程的随机种子大概率完全相同,最终生成的随机数序列完全一致,不符合预期的随机休眠效果。
4. 标准输出无同步保护
多线程并发写std::cout没有加锁,会出现输出内容穿插、乱序的问题。
修复方案示例
最简单的参数传递修复方法是直接把id值转成void*传递,避免栈内存引用:
// 修改createThread调用逻辑,直接传值 pthread_t createThread(int number){ pthread_t id; // 把int强转成void*传值,不需要传地址 int rc = pthread_create(&id, NULL, philFunc, (void*)(long long)number); if(rc){ abort(); } return id; } void *philFunc(void *arg){ // 直接转成int拿到id,不需要解引用 int id = (int)(long long)arg; // 修正leftSpoon边界 int leftSpoon = (id>0) ? id-1 : PHILOSOPHERS - 1; int rightSpoon = id; int i = 0; while(i < 10){ usleep((200 - 50) * ( (double)rand() / RAND_MAX ) + 50); // 实际使用建议加全局互斥锁保护cout输出,避免内容乱序 std::cout << id+1 << " PHILOSOPHER: thinking" << std::endl; ++i; } return nullptr; }
同时把srand(time(0))移到main函数主线程中执行一次即可。
内容的提问来源于stack exchange,提问作者Enkidu
相关产品推荐
相关产品推荐

