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

C语言中基于信号量的线程同步问题:公交模拟中学生下车异常的修复求助

C语言中基于信号量的线程同步问题:公交模拟中学生下车异常的修复求助

兄弟,我看了你的代码和问题描述,核心问题出在条件变量的信号发送方式、临界区的保护逻辑上,还有信号量的用法也存在逻辑偏差,咱们一步步拆解问题并给出修复方案:

核心问题分析

  1. 条件变量唤醒方式错误
    你在公交routine里用了pthread_cond_signal,这个函数只会唤醒单个等待该条件的线程。但公交到站后,应该是所有在对应站点等车/准备下车的学生都能收到通知,所以用signal就会导致大部分学生线程一直处于等待状态——这就是你看到只有Student 1下车的直接原因!

  2. 共享资源未正确加锁
    你修改bus->department_capacity、stop_A、bus_array这些全局共享资源时,没有用互斥锁保护,多个线程同时操作这些资源会引发竞态条件,导致部门人数计数错误、上下车状态混乱等问题。

  3. 信号量用法逻辑错误
    你在学生routine开头就调用sem_wait(&semaphore),直到整个学生流程(上车、上学、放学、回家)结束才sem_post,这相当于同一时间只能有一个学生线程运行,完全违背了多学生并发的场景设计。如果这个信号量是用来限制同时存在的学生数量,逻辑也应该放在线程创建阶段,而不是routine内部。

具体修复步骤

1. 替换条件变量的唤醒方式

把公交routine里的pthread_cond_signal全部改成pthread_cond_broadcast,这样公交到站后会唤醒所有等待该站点条件的线程,同时调整位置更新的顺序(确保状态先更新再通知):

// 公交到A站的代码修改
bus->bus_position = Stop_A;     // 先更新位置
printf(ANSI_BLUE "Bus arrived at Stop A" ANSI_RESET "\n" );
print_areas();
pthread_cond_broadcast(&cond_A);   // 广播唤醒所有等A站的线程
sleep(BUS_WAIT_TIME);

// 公交到B站的代码修改同理
bus->bus_position = Stop_B;
printf(ANSI_BLUE "Bus arrived at Stop B" ANSI_RESET "\n");
print_areas();
pthread_cond_broadcast(&cond_B);
sleep(BUS_WAIT_TIME);

2. 给所有共享资源操作加锁保护

所有修改全局共享数据的代码,都要放在pthread_mutex_lock和pthread_mutex_unlock之间,比如学生从A站上车的逻辑:

// 学生从A站上车的修改后代码
pthread_mutex_lock(&mutex);
// 锁内检查条件,确保线程安全
while(bus->bus_position != Stop_A || !check_department(student)){
    pthread_cond_wait(&cond_A, &mutex);
}
// 修改共享资源
bus->department_capacity[student->department]--;
stop_A[student->AM - 1] = -1;
bus_array[student->AM - 1] = student->AM;
pthread_mutex_unlock(&mutex);

printf(ANSI_GREEN "Student %d is boarding the bus from Stop A" ANSI_RESET "\n", student->AM);
print_areas();

同理,学生下车、从B站上车、回家时修改共享资源的操作,都要加上互斥锁保护。

3. 调整信号量的用法(或移除)

如果你的信号量是用来限制同时运行的学生线程总数,应该把sem_wait放在创建学生线程之前,sem_post放在学生线程结束后:

// 主线程创建学生线程时的逻辑示例
for(int i=0; i<4; i++){
    sem_wait(&semaphore);
    pthread_create(&student_threads[i], NULL, student_routine, (void*)&student_ids[i]);
}

// 学生routine末尾只保留sem_post
sem_post(&semaphore);
return NULL;

如果不需要限制线程总数,直接移除这个信号量即可,因为互斥锁+条件变量已经能满足同步需求。

4. 修正学生ID的传递逻辑

你在search_node(student_list, (int)argv)里把指针直接转成int,这在64位系统上会有截断问题,应该改成:

int student_id = *(int*)argv;
struct student* student = search_node(student_list, student_id);

额外注意点

  • pthread_cond_wait会自动释放互斥锁,被唤醒后会重新获取锁,所以你的条件检查必须放在while循环里(这点你做对了,要保持,因为线程被唤醒后可能条件已经不满足了)。

按照这些修改,你应该能解决只有单个学生下车的问题,同时让整个公交模拟的同步逻辑正常运行。

备注:内容来源于stack exchange,提问作者Jukeland

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 08:39:30