当前位置: 首页 > news >正文

Zephyr OS 中的 FIFO 接口应用介绍

目录

概述

1 FIFO的接口函数

1.1 K_FIFO_DEFINE函数

1.2 k_fifo_init函数

 1.3 k_fifo_put函数

1.4 k_fifo_get 函数

1.5  k_fifo_is_empty 函数

2  应用验证 

2.1  UART中使用FIFO范例

2.2 生产-消费类型范例

3 注意事项

3.1 内存管理

3.2 线程安全边界


概述

Zephyr RTOS 提供了多种 FIFO (First-In-First-Out) 实现方式,适用于不同场景的数据缓冲需求。以下是主要的 FIFO 接口和使用方法。

1 FIFO的接口函数

FIFO 接口主要API如下这些,其具体函数如下:

函数描述
K_FIFO_DEFINE(name)定义并初始化FIFO
k_fifo_init(fifo)运行时初始化FIFO
k_fifo_put(fifo, data)向FIFO放入数据
k_fifo_get(fifo, timeout)从FIFO获取数据
k_fifo_is_empty(fifo)检查FIFO是否为空

1.1 K_FIFO_DEFINE函数

K_FIFO_DEFINE 是 Zephyr RTOS 中用于定义和初始化 FIFO(先进先出队列)的宏,它是 Zephyr 内核提供的一种线程安全的数据传递机制。

1) 基本语法

K_FIFO_DEFINE(name)

2)功能说明

  1. 作用

    • 静态定义并初始化一个 FIFO 队列

    • 创建的 FIFO 可以被多个线程安全地访问

    • 支持阻塞和非阻塞操作

  2. 特性

    • 线程安全:内置同步机制,无需额外锁

    • 动态扩展:基于链表实现,理论上无大小限制

    • 支持超时等待:消费者可以阻塞等待数据

3) 内部实现原理

K_FIFO_DEFINE 实际上创建了一个 struct k_fifo 结构体,其核心实现基于:

  1. 链表结构:使用 Zephyr 的 sys_slist_t 单链表

  2. 同步机制:内置内核信号量保证线程安全

  3. 等待队列:当 FIFO 为空时,允许消费者线程阻塞等待

1.2 k_fifo_init函数

k_fifo_init 是 Zephyr RTOS 中用于运行时初始化 FIFO(先进先出队列)的函数,与静态初始化宏 K_FIFO_DEFINE 相对应,提供了动态初始化 FIFO 的能力。

1)函数原型

void k_fifo_init(struct k_fifo *fifo);

2)参数说明

参数说明

参数类型描述
fifostruct k_fifo*指向要初始化的FIFO结构体的指针

3) 核心功能

  1. 初始化FIFO内部状态

    • 初始化链表头(用于存储数据项)

    • 初始化等待队列(用于阻塞的消费者线程)

    • 重置所有内部状态标志

  2. 线程安全保证

    • 初始化后的FIFO可安全用于多线程环境

    • 内置同步机制,无需额外锁

 3)使用范例

1. 动态创建FIFO

#include <zephyr/kernel.h>struct k_fifo my_fifo;void init_my_fifo(void)
{k_fifo_init(&my_fifo);
}

2. 模块化设计中的FIFO初始化

// 模块头文件
struct data_processor {void *fifo_reserved;// 其他成员...
};// 模块实现
int data_processor_init(struct data_processor *proc)
{if (proc == NULL) {return -EINVAL;}k_fifo_init(&proc->input_fifo);// 其他初始化...return 0;
}

4) 与K_FIFO_DEFINE对比

特性k_fifo_initK_FIFO_DEFINE
初始化方式运行时动态初始化编译时静态初始化
存储位置需自行管理内存自动分配在全局数据区
使用场景动态创建的对象需要FIFO时全局或模块级FIFO
线程安全
初始化时机显式调用时系统启动时自动初始化

 1.3 k_fifo_put函数

k_fifo_put 是 Zephyr RTOS 中用于向 FIFO (先进先出队列) 放入数据项的核心函数,它实现了线程安全的数据生产者-消费者模式。

1)函数原型

void k_fifo_put(struct k_fifo *fifo, void *data);

2)参数说明

参数类型描述
fifostruct k_fifo*指向已初始化的FIFO对象的指针
datavoid*要放入队列的数据项指针

 3)核心功能与特性

  1. 线程安全操作

    • 内部使用内核锁保证多线程/中断环境下的安全访问

    • 支持多生产者并发写入

  2. 唤醒机制

    • 如果有线程在 k_fifo_get 上阻塞等待数据,会自动唤醒最早等待的线程

    • 唤醒的线程将获得刚放入的数据项

  3. 无阻塞设计

    • 函数立即返回,不会阻塞调用线程

    • 适合在中断上下文使用(需配合 K_NO_WAIT 内存分配)

  4. 数据所有权转移

    • 数据项所有权从生产者转移到FIFO,再由消费者获取

    • 放入后生产者不应再访问该数据项

 4)使用示例

-1) 基础使用模式

#include <zephyr/kernel.h>// 定义数据结构
struct sensor_data {void *fifo_reserved;int32_t temperature;uint32_t timestamp;
};K_FIFO_DEFINE(sensor_fifo);void sampling_thread(void)
{while (1) {// 动态分配数据项struct sensor_data *data = k_malloc(sizeof(*data));// 填充数据data->temperature = read_temperature();data->timestamp = k_uptime_get_32();// 放入FIFOk_fifo_put(&sensor_fifo, data);k_sleep(K_MSEC(1000));}
}

-2) 中断上下文使用

void isr_handler(const struct device *dev, void *user_data)
{static struct event_data *evt;if (!evt) {// 预分配避免ISR中动态分配evt = k_malloc(sizeof(*evt));}if (evt) {evt->event_type = DEVICE_EVENT;evt->event_code = read_event_code();// ISR中只能使用非阻塞操作if (k_fifo_put(&event_fifo, evt) == 0) {evt = NULL;  // 成功放入后重置指针}}
}

 5) 与相关函数对比

函数特点适用场景
k_fifo_put单数据项放入通用场景
k_fifo_put_list批量放入多个数据项批量生产场景
k_fifo_put_slist使用系统单链表批量放入已有链表结构的场景
k_queue_alloc_append带内存分配的放入需要自动分配内存的场景

1.4 k_fifo_get 函数

k_fifo_get 是 Zephyr RTOS 中用于从 FIFO (先进先出队列) 获取数据项的核心函数,它实现了线程安全的消费者接口,支持阻塞和非阻塞两种模式。

1)函数原型

void *k_fifo_get(struct k_fifo *fifo, k_timeout_t timeout);

2)参数说明

参数类型描述
fifostruct k_fifo*指向已初始化的FIFO对象的指针
timeoutk_timeout_t指定等待超时时间,可以是:
K_NO_WAIT(非阻塞)
K_FOREVER(永久阻塞)
具体时间值

3)返回值

  • 成功时:返回获取到的数据项指针

  • 超时或失败:返回 NULL

 4)核心功能和特性

  1. 线程安全操作

    • 内部使用内核锁保证多线程环境下的安全访问

    • 支持多消费者并发获取

  2. 灵活的等待策略

    • 非阻塞模式(K_NO_WAIT):立即返回,不等待

    • 阻塞模式:可以指定超时时间或无限等待(K_FOREVER)

    • 定时等待:如 K_MSEC(100) 表示最多等待100毫秒

  3. 优先级继承

    • 当多个线程等待同一个FIFO时,高优先级线程会优先被唤醒

  4. 内存所有权转移

    • 获取到的数据项所有权从FIFO转移到消费者

    • 消费者负责后续的内存管理(通常需要释放)

 5)使用范例

-1)基础使用模式

#include <zephyr/kernel.h>K_FIFO_DEFINE(data_fifo);void consumer_thread(void)
{while (1) {// 阻塞等待数据,最多等待200msstruct sensor_data *data = k_fifo_get(&data_fifo, K_MSEC(200));if (data != NULL) {// 处理数据process_data(data);// 释放内存k_free(data);} else {// 超时处理handle_timeout();}}
}

-2)多消费者协作模式

void consumer_group(void)
{struct k_fifo *fifo = &shared_fifo;while (1) {void *data = k_fifo_get(fifo, K_FOREVER);// 根据数据类型分发处理if (is_type_a(data)) {process_type_a(data);} else if (is_type_b(data)) {process_type_b(data);}k_free(data);}
}

 -3)检查返回值

// 错误:未检查返回值
struct data *item = k_fifo_get(&fifo, K_MSEC(100));
item->value = 0;  // 可能解引用NULL// 正确:必须检查返回值
struct data *item = k_fifo_get(&fifo, K_MSEC(100));
if (item != NULL) {// 安全访问process(item);k_free(item);
}

-4)内存管理责任

void *data = k_fifo_get(&fifo, K_FOREVER);
process(data);
k_free(data);  // 必须释放

1.5  k_fifo_is_empty 函数

k_fifo_is_empty 是 Zephyr RTOS 中用于检查 FIFO (先进先出队列) 是否为空的辅助函数,它提供了一种非破坏性的方式来查询 FIFO 的当前状态。

1)函数原型

bool k_fifo_is_empty(struct k_fifo *fifo);

2)参数说明

参数类型描述
fifostruct k_fifo*指向已初始化的FIFO对象的指针

3) 返回值

  • true:FIFO 为空(没有数据项)

  • false:FIFO 不为空(至少有一个数据项)

 4)核心功能与特性

  1. 非破坏性检查

    • 仅查询状态,不会修改FIFO内容

    • 不会影响任何等待线程

  2. 线程安全

    • 内部使用内核锁保证多线程环境下的安全访问

    • 可以在任何上下文中调用(包括中断)

  3. 轻量级操作

    • 比 k_fifo_get 更轻量,适合状态检查

    • 无阻塞,立即返回结果

5)使用范例

-1)基本使用模式

#include <zephyr/kernel.h>K_FIFO_DEFINE(data_fifo);void consumer_thread(void)
{// 先检查是否有数据if (!k_fifo_is_empty(&data_fifo)) {struct data_item *item = k_fifo_get(&data_fifo, K_NO_WAIT);process_item(item);k_free(item);} else {printk("No data available\n");}
}

-2) 中断上下文使用

void isr_handler(const struct device *dev, void *user_data)
{// 在ISR中安全检查FIFO状态if (!k_fifo_is_empty(&isr_fifo)) {// 可以安全地从ISR中获取数据(非阻塞)struct isr_event *evt = k_fifo_get(&isr_fifo, K_NO_WAIT);handle_isr_event(evt);}
}

-3) 多线程协调

void worker_thread(void)
{while (1) {// 先非阻塞检查if (k_fifo_is_empty(&work_queue)) {// 无工作时休眠k_sleep(K_MSEC(100));continue;}// 有工作则获取处理struct work_item *item = k_fifo_get(&work_queue, K_NO_WAIT);process_work_item(item);k_free(item);}
}

5) 关键注意事项

-1)  竞态条件

// 错误用法:检查和使用之间存在时间间隙
if (!k_fifo_is_empty(&fifo)) {// 在这期间可能有其他线程取走数据item = k_fifo_get(&fifo, K_NO_WAIT);  // 可能得到NULL
}// 正确用法:直接使用k_fifo_get的超时机制
item = k_fifo_get(&fifo, K_NO_WAIT);
if (item != NULL) {// 安全处理
}

-2)  性能考虑:不应作为主要的数据获取机制

// 优化:避免不必要的阻塞
if (!k_fifo_is_empty(&fifo)) {item = k_fifo_get(&fifo, K_NO_WAIT);// 处理item...
}

-3) 与 k_fifo_get 的关系

函数特点适用场景
k_fifo_is_empty仅检查状态,不修改FIFO需要预先知道状态的场景
k_fifo_get获取数据并修改FIFO状态实际消费数据的场景

6)  特性

k_fifo_is_empty 作为 Zephyr FIFO 机制的辅助函数,虽然简单但非常实用。它最适合用于状态监控、性能优化和资源管理场景,而不应作为数据消费的主要机制。正确使用时可以构建出更高效和响应性更好的系统,但需要注意避免常见的竞态条件陷阱。

2  应用验证 

2.1  UART中使用FIFO范例

Step-1:  定义FIFO

 /* UART payload buffer element size. */#define UART_BUF_SIZE 20struct uart_data_t {void *fifo_reserved;uint8_t  data[UART_BUF_SIZE];uint16_t len;};static K_FIFO_DEFINE(fifo_uart_tx_data);static K_FIFO_DEFINE(fifo_uart_rx_data);

Step-2: 使用k_fifo_put准备数据

  struct uart_data_t *tx = k_malloc(sizeof(*tx));err = uart_tx(uart, tx->data, tx->len, SYS_FOREVER_MS);if (err) {k_fifo_put(&fifo_uart_tx_data, tx);}

Step-3: 使用k_fifo_get消费数据

 buf = k_fifo_get(&fifo_uart_tx_data, K_NO_WAIT);if (!buf) {return;}if (uart_tx(uart, buf->data, buf->len, SYS_FOREVER_MS)) {LOG_WRN("Failed to send data over UART");}

2.2 生产-消费类型范例

3 注意事项

3.1 内存管理

// 正确:确保数据项在消费前有效
struct data_item *item = k_malloc(sizeof(*item));
k_fifo_put(fifo, item);// 错误:栈变量在离开作用域后无效
struct data_item item;
k_fifo_put(fifo, &item);  // 严重错误!

3.2 线程安全边界

  • FIFO操作本身是线程安全的

  • 但数据内容的安全性需要开发者自己保证

示例安全模式:

// 生产者
struct data *item = k_malloc(sizeof(*item));
item->value = compute_value();  // 在放入FIFO前完成所有数据准备
k_fifo_put(fifo, item);        // 之后不再修改item// 消费者
struct data *item = k_fifo_get(fifo, K_FOREVER);
use_value(item->value);        // 安全使用数据
k_free(item);

相关文章:

  • deepin v23.1 音量自动静音问题解决
  • 【汇总】影视仓接口地址,影视仓最新配置接口【2025.5】
  • 全栈项目搭建指南:Nuxt.js + Node.js + MongoDB
  • 【深度学习-Day 12】从零认识神经网络:感知器原理、实现与局限性深度剖析
  • 第三章 流程控制
  • Linux面试题集合(4)
  • C++文件操作--2 二进制文件操作
  • 第9讲、深入理解Scaled Dot-Product Attention
  • 重庆 ICPC 比赛游记
  • 信贷域——互联网金融业务
  • 哈希的原理、实现
  • 【OpenGL学习】(二)OpenGL渲染简单图形
  • 系统架构设计(八):三层架构
  • SVN 版本控制入门指南
  • Qt与Hid设备通信
  • Python多进程编程执行任务
  • Class类的详细说明
  • Go语言 GORM框架 使用指南
  • Unity 人物模型学习笔记
  • Windows 上安装下载并配置 Apache Maven
  • 101岁陕西省军区原司令员冀廷璧逝世,曾参加百团大战
  • 阿里上财年营收增6%,蒋凡:会积极投资,把更多淘宝用户转变成即时零售用户
  • 租车订单时隔7年从花呗免密扣费?“GoFun出行”引质疑
  • 讲座|消逝之钟:《红楼梦》与《布登勃洛克一家》中的时间观
  • 龚正会见哥伦比亚总统佩特罗
  • 湖北宜化拟斥资超32亿加价回购“弃子”,布局上游煤炭业务