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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 00:45:01