信号量
本页依据 文档基线与后续更新 中记录的 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 存储数据; 不要仅靠二值信号量统计事件次数。