信号量

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

信号量保存非负计数和上限。k_sem_give() 释放一个单位, k_sem_take() 尝试取得一个单位。二值信号量把上限设为 1;计数信号量可代表多个同类资源。

定义与使用

#include <zephyr/kernel.h>
#include <errno.h>

K_SEM_DEFINE(data_ready, 0, 1);

void notify_from_isr(void)
{
    k_sem_give(&data_ready);
}

int wait_for_data(void)
{
    return k_sem_take(&data_ready, K_MSEC(100));
}

动态初始化使用 k_sem_init(&sem, initial_count, limit),要求上限非零且初值不超过上限。 有等待者时,give 会让等待线程获得信号量;没有等待者时增加计数,最多到配置上限。 多个等待者通常按优先级、同优先级等待顺序选择。

返回值与 ISR

  • k_sem_take() == 0:成功取得。

  • -EBUSY:K_NO_WAIT 时计数不可用。

  • -EAGAIN:等待超时,或等待因 reset 结束。

线程可等待,ISR 可 give,也可使用 K_NO_WAIT 尝试 take,但不能阻塞。 以上返回值要在实际调用点处理;等待失败时不能继续执行只允许取得信号量后执行的操作。

计数、重置与数据

k_sem_count_get() 只返回查询瞬间的计数。另一个线程或中断可能立即改变它, 应直接检查 k_sem_take() 的结果,避免“先看计数、再 take”的竞争。

k_sem_reset() 将计数清零并结束相关等待,适合明确的状态重置流程。 信号量不记录所有者,不提供互斥量的优先级继承。保护共享结构通常使用 互斥量。

上限为 1 时,多次通知可能合并。如果每次采样都必须保留,使用消息队列或 FIFO 存储数据; 不要仅靠二值信号量统计事件次数。

上游依据