pthread_cond_wait与pthread_cond_signal调用顺序及代码正确性咨询
问题分析与修复方案
核心异常原因
你的代码运行失败的核心是条件变量信号丢失,和pthread_cond_signal、pthread_cond_wait的调用先后顺序没有直接关系。
Linux 系统的线程调度顺序是不确定的,你的代码存在两种调度场景:
- 若display线程先拿到锁、进入
pthread_cond_wait状态:此时entry线程输入后发信号可以正常唤醒display,程序运行符合预期 - 若entry线程先拿到锁,完成输入、发信号、释放锁、退出全程后,display线程才拿到锁调用
pthread_cond_wait:此时信号已经发送完成且没有被保存,display线程会永远阻塞等待,就是你遇到的异常场景。
条件变量的正确使用规则
条件变量本身不保存状态,仅负责发送状态变化通知,必须搭配谓词(状态标记)使用,不能直接裸调用pthread_cond_wait。你需要额外新增一个状态标记,判断共享数据是否已经准备完成,即使信号提前发送,也可以通过状态标记感知到,不需要进入等待。
修正后的完整代码
#include <stdio.h> #include <stdlib.h> #include <pthread.h> pthread_mutex_t lockid; pthread_cond_t cvar = PTHREAD_COND_INITIALIZER; char name[14]; // 新增谓词标记:标记姓名是否已经输入完成 int name_ready = 0; void *entry() { pthread_mutex_lock(&lockid); printf("Enter Name\n"); // 限制输入长度避免数组越界 scanf("%13s", name); // 先修改状态标记,再发信号 name_ready = 1; pthread_cond_signal(&cvar); pthread_mutex_unlock(&lockid); pthread_exit(NULL); } void *display() { pthread_mutex_lock(&lockid); // 循环判断谓词,同时可以避免虚假唤醒问题 while (!name_ready) { pthread_cond_wait(&cvar, &lockid); } printf("Name: %s\n", name); pthread_mutex_unlock(&lockid); pthread_exit(NULL); } int main() { pthread_t id1, id2; if(pthread_mutex_init(&lockid, NULL) == 0){ pthread_create(&id1, NULL, entry, NULL); pthread_create(&id2, NULL, display, NULL); pthread_join(id1, NULL); pthread_join(id2, NULL); // 用完销毁互斥锁和条件变量 pthread_mutex_destroy(&lockid); pthread_cond_destroy(&cvar); } return 0; }
额外注意事项
pthread_cond_wait返回时会自动重新持有传入的互斥锁,不需要手动额外加锁- 必须用循环而不是if判断谓词,避免条件变量的虚假唤醒问题
- 原有代码的
scanf没有做长度限制,输入超过13个字符会造成栈溢出,修正后增加了长度限制 - 程序退出前需要销毁初始化完成的互斥锁和条件变量,避免资源泄漏
内容的提问来源于stack exchange,提问作者Meganathan J
相关产品推荐
相关产品推荐

