#C 语言标准库函数 cnd_init
/*********************************************
* @brief 创建条件变量
* @param[out] cond 返回条件变量 ID
* @return 是否成功
********************************************/
int cnd_init(cnd_t* cond);
说明
创建一个条件变量,通过参数 cond
返回条件变量 ID。
不再使用时需要通过 cnd_destroy 函数清理条件变量。
条件变量能够原子地解锁互斥量并阻塞当前线程,从而高效地进入等待;当条件变量收到信号时,线程被唤醒并再次锁定互斥量。
参数
cond
- 返回条件变量 ID
返回值
- 成功时返回
thrd_success
- 内存不足时返回
thrd_nomem
- 其它失败返回
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
说明:
这个示例通过条件变量实现两个线程交替打印。
如果不用条件变量,一个线程要等待某个“条件”成立(例如示例中 turn
的值),它只能用轮询的方式:
while (turn != 1)
{
// 一直检查,CPU空转,浪费资源
}
这会导致 CPU 忙等(busy-waiting),既浪费性能,又不利于调度。
条件变量的出现就是为了解决这个问题:
-
线程在条件不满足时调用 cnd_wait,解锁互斥量并阻塞当前线程,不消耗 CPU;
-
当另一个线程改变了条件,它调用 cnd_signal 或 cnd_broadcast 唤醒等待的线程;
-
被唤醒的线程会再次加锁互斥量,用户应当重新检查条件,如果满足,就继续运行。
#推荐阅读
- C 语言标准库函数 cnd_destroy
- C 语言标准库函数 cnd_wait
- C 语言标准库函数 cnd_signal
- C 语言标准库函数 cnd_broadcast
- cnd_init - cppreference
#参考标准
- C17 standard (ISO/IEC 9899:2018):
- 7.26.3.3 The cnd_init function (p: 276)
- C11 standard (ISO/IEC 9899:2011):
- 7.26.3.3 The cnd_init function (p: 379)