国际访客建议访问 Primers 编程伙伴 国际版站点 > C 教程 > cnd_wait 以获得更好的体验。

# C 语言标准库函数 cnd_wait

在头文件 threads.h 中定义。
/*********************************************
 * @brief 等待条件变量上收到信号
 * @param cond 要等待的条件变量 ID
 * @param mtx 要解锁的互斥量 ID
 * @return 是否成功
 ********************************************/
int cnd_wait(cnd_t* cond, mtx_t* mtx);

!subtitle:说明

原子地解锁互斥量 mtx 并阻塞当前线程,直到条件变量 cond 上收到 cnd_signalcnd_broadcast 发送的信号时唤醒线程并重新锁定互斥量 mtx

这个函数可能发生虚假的唤醒,即条件变量上并没有收到信号,线程却被唤醒并返回 thrd_success;这是由于内存(缓存)可见性延迟、硬件优化、内存屏障、线程调度、系统信号等原因导致的正常现象。

因此,标准做法是:

mtx_lock(&mutex);               // 锁定条件变量
while (!条件) {                 // 循环检查条件,唤醒时会再次检查
    cnd_wait(&cond, &mutex);    // 等待:原子地解锁互斥量并阻塞,唤醒时自动锁定互斥量
}
mtx_unlock(&mutex);             // 解锁条件变量

而不是:

mtx_lock(&mutex);               // 锁定条件变量
if (!条件) {                    // 检查条件,唤醒时直接结束
    cnd_wait(&cond, &mutex);    // 等待:原子地解锁互斥量并阻塞,唤醒时自动锁定互斥量
}
mtx_unlock(&mutex);             // 解锁条件变量

// 错误,这里条件不一定成立
// 即使 cnd_signal 或 cnd_broadcast 时正确设置了条件
// 因为可能虚假的唤醒

!subtitle:参数

  • cond - 要等待的条件变量 ID

  • mtx - 要解锁的互斥量 ID

!subtitle:返回值

  • 成功时返回 thrd_success

  • 失败时返回 thrd_error

# 示例

#include <stdio.h>
#include <threads.h>

// 全局变量
mtx_t mutex;        // 互斥量
cnd_t cond;         // 条件变量
int turn = 1;       // 1 表示线程 1 打印,2 表示线程 2 打印 

// 线程函数1
int func1(void* data)
{
    // 与线程 2 交替打印
    for (int i = 0; i < 10; i++)
    {
        mtx_lock(&mutex);               // 锁定互斥量
        while (turn != 1)
        {
            cnd_wait(&cond, &mutex);    // 等待信号
        }
        printf("线程1: %d\n", i);
        turn = 2;
        cnd_signal(&cond);              // 发送信号,唤醒线程 2
        mtx_unlock(&mutex);             // 解锁互斥量
    }
    
    return 0;
}

// 线程函数2
int func2(void* data)
{
    // 与线程 1 交替打印
    for (int i = 0; i < 10; i++)
    {
        mtx_lock(&mutex);               // 锁定互斥量
        while (turn != 2)
        {
            cnd_wait(&cond, &mutex);    // 等待信号
        }
        printf("线程2: %d\n", i);
        turn = 1;
        cnd_signal(&cond);              // 发送信号,唤醒线程 1
        mtx_unlock(&mutex);             // 解锁互斥量
    }
    
    return 0;
}

int main(void)
{
    mtx_init(&mutex, mtx_plain);    // 创建互斥量
    cnd_init(&cond);                // 创建条件变量

    // 创建线程
    thrd_t th1, th2;
    thrd_create(&th1, func1, NULL);
    thrd_create(&th2, func2, NULL);

    // 等待线程结束
    thrd_join(th1, NULL);
    thrd_join(th2, NULL);

    // 清除互斥量和条件变量
    mtx_destroy(&mutex);
    cnd_destroy(&cond);
    
    return 0;
}

!subtitle:运行结果

线程1: 0
线程2: 0
线程1: 1
线程2: 1
线程1: 2
线程2: 2
线程1: 3
线程2: 3
线程1: 4
线程2: 4
线程1: 5
线程2: 5
线程1: 6
线程2: 6
线程1: 7
线程2: 7
线程1: 8
线程2: 8
线程1: 9
线程2: 9

!subtitle:说明

这个示例通过条件变量实现两个线程交替打印。

# 推荐阅读

# 参考标准

  • C17 standard (ISO/IEC 9899:2018):

    • 7.26.3.6 The cnd_wait function (p: 277)

  • C11 standard (ISO/IEC 9899:2011):

    • 7.26.3.6 The cnd_wait function (p: 380)

本文 更新于: 2025-11-27 09:38:08 创建于: 2025-11-27 09:38:08