FIFO 与 LIFO

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

FIFO 按进入顺序取出对象,LIFO 优先取出最后加入的对象。二者都传递对象地址, 不会自动复制应用载荷。等待者的调度优先级与队列中数据的顺序是两个独立概念。

定义与内存布局

普通 k_fifo_put()、k_lifo_put() 要求数据按本机字对齐,并保留首个字供内核链接。 可在结构体首部放置 void *:

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

struct sample {
    void *fifo_reserved;
    uint32_t value;
};

K_FIFO_DEFINE(samples);
K_MEM_SLAB_DEFINE(sample_pool, sizeof(struct sample), 8, sizeof(void *));

int enqueue_sample(uint32_t value)
{
    struct sample *item;
    int rc = k_mem_slab_alloc(&sample_pool, (void **)&item, K_NO_WAIT);

    if (rc != 0) {
        return rc;
    }
    item->value = value;
    k_fifo_put(&samples, item);
    return 0; /* 所有权交给消费者 */
}

int dequeue_sample(uint32_t *value)
{
    struct sample *item = k_fifo_get(&samples, K_MSEC(100));

    if (item == NULL) {
        return -EAGAIN;
    }
    *value = item->value;
    k_mem_slab_free(&sample_pool, item);
    return 0;
}

同一对象同时只能处于一个队列中,取出前不得重复 put。 示例用 slab 管理生命周期,避免把生产者的临时栈变量排队后立即失效。

动态包装与批量插入

k_fifo_alloc_put()、k_lifo_alloc_put() 为链接信息申请额外包装存储, 因此数据对象不必自行预留首字。此分配使用调用线程的资源池,可能失败; 它仍然没有复制或取得应用载荷的永久所有权。

FIFO 支持 k_fifo_put_list() 和 k_fifo_put_slist() 批量加入链表。 链表的组织方式必须符合对应接口要求。LIFO 使用 K_LIFO_DEFINE、k_lifo_put()、k_lifo_get(),取出顺序相反。

读取与等待

get 成功返回对象指针,无数据、超时或取消等待时返回 NULL,应在解引用前检查。 线程可等待,ISR 只能使用 K_NO_WAIT。存在等待者时,新数据可直接交给等待线程。

FIFO 可配合 轮询多个内核对象 等待,但 poll 不预留数据,之后的 get 仍可能返回 NULL。 不要依赖 k_queue 内部节点标记或链表字段的历史实现来编写应用。

上游依据