3340

17 分钟

#C 语言标准库函数 cnd_wait

/********************************************* * @brief 等待条件变量上收到信号 * @param cond 要等待的条件变量 ID * @param mtx 要解锁的互斥量 ID * @return 是否成功 ********************************************/ int cnd_wait(cnd_t* cond, mtx_t* mtx);

说明

原子地解锁互斥量 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 时正确设置了条件 // 因为可能虚假的唤醒

参数

  • cond - 要等待的条件变量 ID
  • mtx - 要解锁的互斥量 ID

返回值

  • 成功时返回 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; }

运行结果

线程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

说明

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

#推荐阅读

#参考标准

  • 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/8/25

更新于 2025/8/25