条件变量

本页依据 文档基线与后续更新 中记录的 Zephyr main 快照更新。

条件变量让线程等待受互斥量保护的应用状态发生变化。它本身不保存“已经通知过几次”, 没有等待者时发出的 signal 不会像信号量计数那样留待以后消费。

等待流程

调用 k_condvar_wait() 前,线程先持有配套互斥量。wait 原子地释放锁并加入等待, 返回前重新获取同一把锁。线程醒来后必须再次检查条件,因为其他线程可能已经消费了资源。

#include <zephyr/kernel.h>

K_MUTEX_DEFINE(value_lock);
K_CONDVAR_DEFINE(value_changed);
static bool ready;
static int value;

int consume_value(int *output)
{
    int result;

    k_mutex_lock(&value_lock, K_FOREVER);
    while (!ready) {
        int rc = k_condvar_wait(&value_changed, &value_lock, K_FOREVER);
        if (rc != 0) {
            k_mutex_unlock(&value_lock);
            return rc;
        }
    }
    result = value;
    ready = false;
    k_mutex_unlock(&value_lock);
    *output = result;
    return 0;
}

void publish_value(int next)
{
    k_mutex_lock(&value_lock, K_FOREVER);
    value = next;
    ready = true;
    k_condvar_signal(&value_changed);
    k_mutex_unlock(&value_lock);
}

这是单槽状态示例,新发布可能替换尚未消费的旧值;需要保留所有值时使用消息队列。 示例通过返回值报告状态,成功时才写入 output。

signal、broadcast 与超时

k_condvar_signal() 唤醒一个等待者,k_condvar_broadcast() 唤醒全部等待者。 状态更新和条件检查应使用同一把互斥量。用 if 代替示例中的 while,可能在竞争 或不满足条件的唤醒后继续处理错误状态。

限时等待应检查返回值,并在返回时处理重新取得的互斥量。如果整个操作有总超时, 每次循环要按剩余时间等待,不能每次唤醒后重新给予完整超时。 不要递归多次持锁后依赖一次 wait 释放全部持锁层次;通常在持锁深度为 1 时等待。 条件变量的等待路径依赖线程与互斥量,不用于 ISR 阻塞。

上游依据