zephyr笔记 2.5.1 FIFOs
1 前言
fifo是实现传统先进先出(FIFO)队列的内核对象,允许线程和ISR添加和删除任何大小的数据项。
我正在学习 Zephyr,一个很可能会用到很多物联网设备上的操作系统,如果你也感兴趣,可点此查看帖子zephyr学习笔记汇总。
2 概念
可以定义任何数量的fifos。 每个fifo由其内存地址引用。
fifo具有以下关键属性:
- 已添加但尚未删除的数据项目队列。队列为一个简单的链表。
fifo必须在可以使用前初始化。这将其队列设置为空。
FIFO数据项必须在4字节的边界上对齐,因为内核保留了项目的前32位,用作指向队列中下一个数据项的指针。因此,保存N字节应用程序数据的数据项需要N + 4字节的内存。
数据项可以由线程或ISR添加到fifo。该项目直接提供给等待的线程(如果存在); 否则该项目将被添加到fifo的队列中。 可能排队的项目数量没有限制。
数据项可以由线程从fifo中移除。如果FIFO的队列是空的,则线程可以选择等待给出数据项。任何数量的线程可以同时等待一个空的fifo。 当数据项被添加时,它被赋予等待时间最长的最高优先级线程。
注意:内核确实允许ISR从FIFO中移除一个项目,但是如果FIFO是空的,ISR不能尝试等待。
如果需要,如果多个数据项链接在一起形成一个单链表,则可以在单个操作中将其添加到FIFO中。 如果多个编写者将相关数据项集合添加到fifo,此功能可能很有用,因为它确保每个集合中的数据项不与其他数据项交错。 将多个数据项添加到fifo比一次添加多个数据项更有效,并且可以用来保证删除组中的第一个数据项的任何人都能够无需等待而删除剩余的数据项。
3 操作
3.1 定义一个FIFO
fifo使用 struct k_fifo 类型的变量来定义。它必须通过调用 k_fifo_init() 来初始化。
以下代码定义并初始化一个空的fifo。
struct k_fifo my_fifo;
k_fifo_init(&my_fifo);
或者,可以通过调用K_FIFO_DEFINE在编译时定义并初始化一个空的fifo。
以下代码与上面的代码段具有相同的效果。
K_FIFO_DEFINE(my_fifo);
3.2 写入FIFO
通过调用 k_fifo_put() 将数据项添加到fifo中。
以下代码构建在上述示例上,并使用fifo将数据发送到一个或多个消费者线程。
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);
...
}
}
此外,可以通过调用 k_fifo_put_list() 或 k_fifo_put_slist() 将单链表数据项添加到fifo中。
3.3 从FIFO中读取
通过调用 k_fifo_get() 从FIFO中删除数据项。
以下代码构建在上述示例上,并使用fifo从生产者线程获取数据项,然后以某种方式处理它们。
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 */
...
}
}
4 建议用法
使用fifo以“先进先出”的方式异步传输任意大小的数据项。
5 配置选项
无
6 APIs
下列 FIFO API,都在 kernel.h 中提供了:
K_FIFO_DEFINE
k_fifo_init()
k_fifo_put()
k_fifo_put_list()
k_fifo_put_slist()
k_fifo_get()