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);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/81993.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot 集成 Elasticsearch【实战】

前言&#xff1a; 上一篇我们简单分享了 Elasticsearch 的一些概念性的知识&#xff0c;本篇我们来分享 Elasticsearch 的实际运用&#xff0c;也就是在 Spring Booot 项目中使用 Elasticsearch。 Elasticsearch 系列文章传送门 Elasticsearch 基础篇【ES】 Elasticsearch …

Win11下轻松搭建wiki.js,Docker.desktop部署指南(mysql+elasticsearch+kibana+wiki.js)

Docker.desktop部署wiki.js指南 前言环境和要求介绍提前准备 1. elasticsearch1.1 部署容器1.2 参数说明1.3 验证容器是否部署成功 2. kibana2.1 部署容器2.2 验证是否部署成功2.3 安装IK分词器 3. MySql3.1 部署容器3.2 增加数据库和wiki.js所需要的账号 4. wiki.js4.1 部署容…

PCB设计教程【入门篇】——电路分析基础-元件数据手册

前言 本教程基于B站Expert电子实验室的PCB设计教学的整理&#xff0c;为个人学习记录&#xff0c;旨在帮助PCB设计新手入门。所有内容仅作学习交流使用&#xff0c;无任何商业目的。若涉及侵权&#xff0c;请随时联系&#xff0c;将会立即处理 目录 前言 一、数据手册的重要…

【论文阅读 | AAAI 2025 | FD2-Net:用于红外 - 可见光目标检测的频率驱动特征分解网络】

论文阅读 | AAAI 2025 | FD2-Net&#xff1a;用于红外 - 可见光目标检测的频率驱动特征分解网络 1.摘要&&引言2. 方法2.1总体架构2.2特征分解编码器2.3多模态重建机制2.4训练损失 3.实验3.1实验设置3.2主要结果3.3消融研究 4.结论 题目&#xff1a;FD2-Net: Frequency-…

CAU人工智能class3 优化器

优化算法框架 优化思路 随机梯度下降 随机梯度下降到缺点&#xff1a; SGD 每一次迭代计算 mini-batch 的梯度&#xff0c;然后对参数进行更新&#xff0c;每次迭代更新使用的梯度都只与本次迭代的样本有关。 因为每个批次的数据含有抽样误差&#xff0c;每次更新可能并不会 …

webpack 学习

webpack打包流程及原理 Webpack 是一个现代 JavaScript 应用程序的静态模块打包器&#xff08;module bundler&#xff09;。在 Web 开发中&#xff0c;它主要用于将各种资源&#xff08;如 JavaScript、CSS、图片等&#xff09;打包成浏览器可以直接运行的文件。Webpack 的核…

HTML5中的Microdata与历史记录管理详解

HTML5中的Microdata与历史记录管理解析 一、Microdata结构化数据 核心属性 itemscope 声明数据范围itemtype 指定数据词汇表&#xff08;如http://schema.org/Product&#xff09;itemprop 定义数据属性 <div itemscope itemtype"http://schema.org/Book">…

《算法笔记》11.7小节——动态规划专题->背包问题 问题 A: 装箱问题

【问题描述】 有一个箱子的容量为V&#xff08;V为正整数&#xff0c;且满足0≤V≤20000&#xff09;&#xff0c;同时有n件物品&#xff08;0的体积值为正整数。 要求从n件物品中&#xff0c;选取若干装入箱内&#xff0c;使箱子的剩余空间最小。 输入&#xff1a; 1行整数&a…

Compose笔记(二十五)--Brush

这一节主要了解一下Compose中Brush,在Jetpack Compose里&#xff0c;Brush是一个重要的 API&#xff0c;它用于定义填充图形的颜色渐变或图案&#xff0c;能够为界面元素添加丰富的视觉效果。简单总结如下: 1 常见场景 填充形状&#xff08;圆形、矩形等&#xff09; 创建渐变…

离线服务器Python环境配置指南

离线服务器Python环境配置指南&#xff1a;避坑与实战 0. 场景分析&#xff1a;当服务器与世隔绝时 典型困境&#xff1a; 无法访问国际网络&#xff08;如PyPI、Conda官方源&#xff09;服务器处于内网隔离环境安全策略限制在线安装 解决方案矩阵&#xff1a; 方法适用场…

Mac下载bilibili视频

安装 安装 yt-dlp brew install yt-dlp安装FFmpeg 用于合并音视频流、转码等操作 brew install ffmpeg使用 下载单个视频 查看可用格式 yt-dlp -F --cookies-from-browser chrome "https://www.bilibili.com/video/BV15B4y1G7F3?spm_id_from333.788.recommend_more_vid…

常见的实时通信技术(轮询、sse、websocket、webhooks)

1. HTTP轮询&#xff1a;最老实的办法 刚开始做实时功能时&#xff0c;我第一个想到的就是轮询。特别简单直白&#xff0c;就像你每隔5分钟就刷新一次朋友圈看看有没有新消息一样。 短轮询&#xff1a;勤快但费劲 短轮询就是客户端隔三差五地问服务器&#xff1a;"有新…

Elasticsearch Fetch阶段面试题

Elasticsearch Fetch阶段面试题 🚀 目录 基础原理性能优化错误排查场景设计底层机制总结基础原理 🔍 面试题1:基础原理 题目: 请描述Elasticsearch分布式搜索中Query阶段和Fetch阶段的工作流程,为什么需要将搜索过程拆分为这两个阶段? 👉 点击查看答案 查询流程…

vr制作公司提供什么服务?

随着科技的迅猛进步&#xff0c;虚拟现实&#xff08;Virtual Reality&#xff0c;简称VR&#xff09;技术已经悄然渗透到我们的日常生活与工作中&#xff0c;成为推动数字化转型的重要力量。VR制作公司&#xff0c;作为前沿领域的探索者和实践者&#xff0c;以专业的技术和创新…

COCO数据集神经网络性能现状2025.5.18

根据当前搜索结果&#xff0c;截至2025年5月&#xff0c;COCO数据集上性能最佳的神经网络模型及其关键参数如下&#xff1a; 1. D-FINE&#xff08;中科大团队&#xff09; 性能参数&#xff1a; 在COCO数据集上以78 FPS的速度实现了59.3%的平均精度&#xff08;AP&#xff0…

Sentinel原理与SpringBoot整合实战

前言 随着微服务架构的广泛应用&#xff0c;服务和服务之间的稳定性变得越来越重要。在高并发场景下&#xff0c;如何保障服务的稳定性和可用性成为了一个关键问题。阿里巴巴开源的Sentinel作为一个面向分布式服务架构的流量控制组件&#xff0c;提供了从流量控制、熔断降级、…

Ubuntu 20.04 报错记录: Matplotlib 无法使用 OpenCV 的 libqxcb.so

网上查了一下这个报错&#xff0c;有很多解决方案&#xff0c;但是都不是针对 OpenCV 触发的这种 qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in " */lib/*/site-packages/cv2/qt/plugins" even though it was found. 本文的方案是牺牲 …

配置代理服务器访问github、google

配置代理服务器访问github、google 背景与原理配置环境配置步骤云主机配置Windows客户端创建SSH隧道安装 Windows 内置 OpenSSHssh config 配置文件创建动态代理隧道 浏览器代理设置 验证浏览器访问google、githubssh 访问github 背景与原理 由于网络政策限制&#xff0c;中国…

网络学习-利用reactor实现http请求(六)

一、实现HTTP请求 1、印象里面&#xff0c;总有人说C/C语言不能实现HTTP请求&#xff0c;其实不然。C/C语言完全可以实现HTTP请求。通过对select,poll,epoll等IO多路复用技术的学习以及reactor模式的学习&#xff0c;完全能够实现HTTP请求。 2、webserver 主要解决两个问题 …

【VSCode】修改侧边文件资源管理器中的文件夹折叠模式

默认为紧凑模式&#xff1a; 然后我们勾选该项为宽松模式&#xff1a;