终端中Semaphores运行异常,不同环境下同一段多线程代码输出结果不一致
问题原因分析
1. 线程调度策略的平台差异
你的代码执行流中,以下逻辑是确定的:
- 信号量
mySem初始值为0,先创建的p1线程会立刻阻塞在sem_wait(&mySem)调用上,必须等p2执行sem_post才会被唤醒,因此p1的printf("B")一定发生在p2的sem_post之后。 - p2的代码逻辑是先执行
printf("A"),再执行sem_post(&mySem)。
但sem_post的语义仅为「唤醒等待该信号量的线程」,并不会强制当前运行的p2线程让出CPU,也没有规范要求被唤醒的p1必须立刻抢占执行:
- 如果平台调度器让p2在
sem_post之后继续运行直到退出,那么printf("A")的内容先输出,之后p1被调度输出B,结果就是AB,也就是replit平台的表现。 - 如果平台调度器在
sem_post完成后优先调度刚被唤醒的p1线程,就会出现p1先执行输出的场景。
2. 标准输出缓冲的干扰
printf默认带缓冲,交互式终端下是行缓冲,非交互式场景下是全缓冲:只有遇到换行符\n、主动调用fflush(stdout)或者程序退出时,缓冲区的内容才会真正写入终端。
你的代码里两次printf都没有加换行符,也没有主动刷缓冲,输出内容的实际显示顺序可能受缓冲刷新时机影响,和printf的调用顺序出现偏差。
验证方案
你可以做两处修改排查问题:
- 给所有
printf增加换行符,或者调用后主动刷缓冲,排除缓冲干扰:
// 修改p2a的printf逻辑 printf("A"); fflush(stdout); sem_post(&mySem); // 修改p1a的printf逻辑 sem_wait(&mySem); printf("B"); fflush(stdout);
- 本地编译时关闭优化选项,添加
-lpthread链接参数,避免编译器指令重排:gcc test.c -o test -lpthread -O0
补充说明
如果需要严格保证A的输出一定在B之前,建议在sem_post前主动刷出标准输出缓冲区,避免平台调度和缓冲的差异导致结果不符合预期。
内容的提问来源于stack exchange,提问作者jotaro
相关产品推荐
相关产品推荐

