C语言线程同步休眠教授问题代码运行异常排查与修正
休眠教授同步问题代码修复
原代码核心错误点
- 互斥锁使用违规:
pthread_cond_wait调用前必须持有绑定的互斥锁,原代码IdleProf函数中调用条件等待前未加锁,后续分支又重复执行加锁操作,直接触发死锁或未定义行为。 - 线程创建逻辑不符合需求:要求仅1个教授线程,原代码按输入的学生数量创建了N个教授线程,还覆盖了线程数组存储的线程ID,导致线程等待、资源回收逻辑完全失效。
- 标准输入传参错误:
scanf读取整数需要传入变量地址,原代码写为scanf("%d",std_nb),缺失地址符&,运行时直接触发段错误。 - 共享状态无保护:等待学生数、教授忙碌状态的读写没有全程被互斥锁覆盖,存在竞态条件。
- 条件等待未处理虚假唤醒:所有
pthread_cond_wait调用仅用if做一次状态判断,没有用循环在wait返回后重新校验条件,遇到虚假唤醒会直接打破同步逻辑。 - 等待计数逻辑错乱:学生到达时如果教授正处于忙碌状态,原逻辑没有正确累加等待学生数,会导致教授无法正确感知等待队列长度。
- 同步逻辑缺失:没有实现“教授和对应学生同时从函数返回”的配对逻辑,会出现教授提前返回接待下一个学生、多个学生同时进入办公室的问题。
修复后可运行代码
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <stdbool.h> #include <unistd.h> pthread_mutex_t mutex; pthread_cond_t prof_wake, student_come; int waiting_stu = 0; bool prof_busy = false; // 标记教授是否已经准备好接待当前学生,保证双方同步返回 bool prof_ready = false; void* IdleProf(void* arg) { while(1) { pthread_mutex_lock(&mutex); prof_busy = 0; prof_ready = 0; // 没有等待学生就休眠 while(waiting_stu == 0) { printf("Professor: no waiting student, go to sleep\n"); pthread_cond_wait(&student_come, &mutex); } // 有等待学生,准备接待 prof_busy = 1; waiting_stu--; printf("Professor: wake up, ready to meet one student\n"); // 通知等待的学生可以进入 prof_ready = 1; pthread_cond_signal(&prof_wake); pthread_mutex_unlock(&mutex); // 模拟交流过程,执行完成后循环重新进入空闲状态 printf("Professor: meeting with student...\n"); sleep(1); printf("Professor: meeting finished, back to idle state\n"); } return NULL; } void* ArrivingStudent(void* arg) { int stu_id = *(int*)arg; pthread_mutex_lock(&mutex); printf("Student %d: arrive at office\n", stu_id); // 累加等待计数 waiting_stu++; // 唤醒休眠的教授 pthread_cond_signal(&student_come); // 等待教授准备好接待 while(!prof_ready) { pthread_cond_wait(&prof_wake, &mutex); } // 收到教授接待信号后,清空准备标记,和教授同时退出临界区返回 prof_ready = 0; pthread_mutex_unlock(&mutex); // 模拟交流过程 printf("Student %d: entering office, asking question...\n", stu_id); sleep(1); printf("Student %d: question solved, go back to study\n", stu_id); return NULL; } int main() { int stu_num; printf("Students Number?: "); scanf("%d", &stu_num); if(stu_num <= 0) { printf("Invalid student number\n"); return 1; } pthread_t prof_tid; pthread_t* stu_tids = (pthread_t*)malloc(sizeof(pthread_t)*stu_num); int* stu_ids = (int*)malloc(sizeof(int)*stu_num); pthread_mutex_init(&mutex, NULL); pthread_cond_init(&prof_wake, NULL); pthread_cond_init(&student_come, NULL); // 仅创建1个教授线程 pthread_create(&prof_tid, NULL, IdleProf, NULL); // 创建对应数量的学生线程 for(int i=0; i<stu_num; i++) { stu_ids[i] = i+1; pthread_create(&stu_tids[i], NULL, ArrivingStudent, &stu_ids[i]); // 加随机间隔模拟学生随机到达 usleep(rand()%1000000); } // 等待所有学生线程结束 for(int i=0; i<stu_num; i++) { pthread_join(stu_tids[i], NULL); } // 资源回收 free(stu_tids); free(stu_ids); pthread_cancel(prof_tid); // 所有学生离开后回收教授线程 pthread_mutex_destroy(&mutex); pthread_cond_destroy(&prof_wake); pthread_cond_destroy(&student_come); return 0; }
代码逻辑说明
- 所有共享状态的读写全部在互斥锁保护范围内,避免竞态
- 条件等待全部采用while循环校验状态,兼容虚假唤醒场景
- 严格保证同一时间只有1名学生和教授配对:教授每次被唤醒后只接待1名学生,发送信号后和学生同时退出临界区,不会出现多学生同时进入的问题
- 学生到达时无论教授是休眠还是忙碌,都会先加入等待队列,再根据状态决定是否唤醒教授,计数逻辑准确
- 仅创建1个教授线程,符合需求设定
内容的提问来源于stack exchange,提问作者ayah
相关产品推荐
相关产品推荐

