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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 06:39:15