Zephyr RTOS -- FIFO (LIFO)

Posted 搬砖-工人

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Zephyr RTOS -- FIFO (LIFO)相关的知识,希望对你有一定的参考价值。

本笔记基于 Zephyr 版本 2.6.0-rc2

 

前言

本人正在学习 Zephyr,一个可移植性较强,可以兼容多种开发板及物联网设备的操作系统,如果你感兴趣,可以点此查看我的 学习笔记总述 进行了解!

 

1. Queues

Zephyr 中的 Queue 是一个内核对象,它实现了一个传统的队列,允许线程和 ISR 添加和删除任何大小的数据项。队列类似于 FIFO,是 k_fifok_lifo 的底层实现。有关用法的更多信息,请参见 k_fifo (k_lifo)。

 

2. FIFOs (LIFOs)

2.1 Concepts

可以定义任意数量的 FIFO(LIFO) (仅受可用 RAM 限制)。每个 FIFO(LIFO) 由其内存地址引用。

FIFO(LIFO) 具有以下关键属性:

  • 已添加但尚未删除的数据项的 队列(queue)。该队列被实现为一个简单的链表。

FIFO(LIFO) 数据项必须在字边界上对齐,因为内核保留项的第一个字,用作指向队列中下一个数据项的指针。 因此,包含 N 字节应用程序数据的数据项需要 N+4 (或 N+8)字节的内存。如果使用 k_fifo_alloc_put() (k_lifo_alloc_put()) 添加数据项,则不需要对齐或预留空间,而是从调用线程的资源池中临时分配额外的内存。

一个数据项可以通过线程或 ISR 添加到 FIFO(LIFO) 中。如果存在等待线程,则直接将该项赋给该线程;否则该项目将被添加到 FIFO(LIFO) 的队列中。对可以排队的项目的数量没有限制。

一个数据项可以由一个线程从 FIFO(LIFO) 中删除。如果 FIFO(LIFO) 的队列是空的,那么线程可以选择等待给定的数据项。任意数量的线程可以同时等待一个空的 FIFO(LIFO)。添加数据项时,会将其分配给等待时间最长的最高优先级线程。

Note:
内核允许 ISR 从 FIFO(LIFO) 中移除一个项目,但是如果 FIFO(LIFO) 是空的,ISR 不能尝试等待。

如果需要,多个数据项可以在单个操作中添加到 FIFO 中,如果它们被链接到一个单链表中。如果多个编写者向 FIFO 添加相关数据项集,则此功能可能非常有用,因为它确保每个数据集中的数据项不与其他数据项交叉。向 FIFO 中添加多个数据项也比一次添加一个数据项更有效,并可用于确保任何删除集合中的第一个数据项的人都能够删除其余的数据项,而无需等待。

 

2.2 Implementation

2.2.1 Defining a FIFO (LIFO)

FIFO(LIFO) 是使用 k_fifo (k_lifo) 类型的变量定义的。然后必须通过调用 k_fifo_init() (k_lifo_init()) 来初始化它。

以下代码定义并初始化一个空的 FIFO(LIFO)。

struct k_fifo my_fifo;

k_fifo_init(&my_fifo);

或

struct k_lifo my_lifo;

k_lifo_init(&my_lifo);

或者,可以在编译时通过调用 K_FIFO_DEFINE (K_LIFO_DEFINE) 来定义和初始化一个空的 FIFO(LIFO)。

下面的代码和上面的代码段效果一样。

K_FIFO_DEFINE(my_fifo);

或

K_LIFO_DEFINE(my_lifo);

 

2.2.2 Writing to a FIFO (LIFO)

通过调用 k_fifo_put() (k_lifo_put()) 将数据项添加到 FIFO(LIFO)。

以下代码建立在上述示例的基础上,并使用 FIFO(LIFO) 将数据发送到一个或多个消费者线程。

struct data_item_t {
    void *fifo_reserved;   /* 1st word reserved for use by FIFO */
    ...
};

struct data_item_t tx_data;

void producer_thread(int unused1, int unused2, int unused3)
{
    while (1) {
        /* create data item to send */
        tx_data = ...

        /* send data to consumers */
        k_fifo_put(&my_fifo, &tx_data);

        ...
    }
}
struct data_item_t {
    void *LIFO_reserved;   /* 1st word reserved for use by LIFO */
    ...
};

struct data_item_t tx data;

void producer_thread(int unused1, int unused2, int unused3)
{
    while (1) {
        /* create data item to send */
        tx_data = ...

        /* send data to consumers */
        k_lifo_put(&my_lifo, &tx_data);

        ...
    }
}

此外,可以通过调用 k_fifo_put_list()k_fifo_put_slist() 将数据项的单向链接列表添加到 FIFO。

最后,可以使用 k_fifo_alloc_put() (k_lifo_alloc_put()) 将数据项添加到 FIFO(LIFO)。使用此 API,无需为内核在数据项中使用预留空间,而是会从调用线程的资源池中分配额外的内存,直到读取该数据项为止。

 

2.2.3 Reading from a FIFO (LIFO)

通过调用 k_fifo_get() 从 FIFO(LIFO) (k_lifo_get()) 中删除数据项。

以下代码建立在上述示例的基础上,并使用 FIFO(LIFO) 从生产者线程获取数据项,然后以某种方式对其进行处理。

void consumer_thread(int unused1, int unused2, int unused3)
{
    struct data_item_t  *rx_data;

    while (1) {
        rx_data = k_fifo_get(&my_fifo, K_FOREVER);

        /* process FIFO data item */
        ...
    }
}
void consumer_thread(int unused1, int unused2, int unused3)
{
    struct data_item_t  *rx_data;

    while (1) {
        rx_data = k_lifo_get(&my_lifo, K_FOREVER);

        /* process LIFO data item */
        ...
    }
}

 

2.3 Suggested Uses

使用 FIFO 以 “先进先出” 的方式异步传输任意大小的数据项。

使用 LIFO 以 “后进先出” 的方式异步传输任意大小的数据项。

 

2.4 Configuration Options

相关配置选项:

  • None

 

参考链接

Queues: https://docs.zephyrproject.org/latest/reference/kernel/data_passing/queues.html

FIFO: https://docs.zephyrproject.org/latest/reference/kernel/data_passing/fifos.html

LIFO: https://docs.zephyrproject.org/latest/reference/kernel/data_passing/lifos.html

以上是关于Zephyr RTOS -- FIFO (LIFO)的主要内容,如果未能解决你的问题,请参考以下文章

Zephyr RTOS -- FIFO (LIFO)

Zephyr RTOS -- Stacks

Zephyr RTOS -- Stacks

Zephyr RTOS -- Stacks

Zephyr RTOS -- Polling API

Zephyr RTOS -- Polling API