轮询多个内核对象
本页依据 文档基线与后续更新 中记录的 Zephyr main 快照更新。
k_poll() 让线程同时等待多个通知,启用 CONFIG_POLL=y。
这里的 poll 是等待内核对象就绪,不是循环忙查设备寄存器。
就绪与取得资源
使用 struct k_poll_event 描述对象及关注类型,模式为 K_POLL_MODE_NOTIFY_ONLY。
常见类型包括信号量可用、FIFO 数据可用、消息队列数据可用,以及用户定义的 poll signal。
当前公共头文件还包含管道数据可用事件。
poll 返回后,对象可能被其他线程先一步消费,仍需使用相应 API 取得资源并检查结果。
例如收到信号量通知后再 k_sem_take(..., K_NO_WAIT),不能假设必定成功。
#include <zephyr/kernel.h>
K_SEM_DEFINE(ready, 0, 1);
static struct k_poll_signal stop_signal = K_POLL_SIGNAL_INITIALIZER(stop_signal);
int wait_ready_or_stop(void)
{
struct k_poll_event events[] = {
K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SEM_AVAILABLE,
K_POLL_MODE_NOTIFY_ONLY, &ready),
K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL,
K_POLL_MODE_NOTIFY_ONLY, &stop_signal),
};
int rc = k_poll(events, ARRAY_SIZE(events), K_MSEC(100));
if (rc != 0) {
return rc;
}
if (events[1].state == K_POLL_STATE_SIGNALED) {
return 1; /* 示例约定:停止;信号保持到明确重置 */
}
if (events[0].state == K_POLL_STATE_SEM_AVAILABLE) {
return k_sem_take(&ready, K_NO_WAIT);
}
return 0;
}
信号与重复等待
k_poll_signal_raise(&signal, result) 置位信号并保存结果。
k_poll_signal_check() 可以读取状态,k_poll_signal_reset() 清除信号。
signal 不是消息队列,多次 raise 不能用来保存多条独立结果。
重复使用事件数组时,在下一轮前把各元素的 state 恢复为 K_POLL_STATE_NOT_READY。
重置信号对象和重置事件数组状态是两件事。应用必须安排好发送者/接收者协议,
避免接收者 reset 刚好擦掉另一个线程的新通知;需要逐条交付时使用队列。
-EAGAIN 表示没有在指定时间内满足条件。取消、参数错误等路径也应按 API 返回值处理。
不要把 poll 的成功返回误认为数组中的每个对象都已就绪,应逐项查看 state。