轮询多个内核对象

本页依据 文档基线与后续更新 中记录的 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。

上游依据