Zephyr RTOS 中LIFOs(后进先出队列)的介绍
目录概述1 LIFO 介绍1.1 核心函数列表1.2 LIFO 的核心概念1.3 LIFO 与其他 IPC 机制的对比2 核心函数详解与使用2.1 初始化 LIFO2.2 添加数据项k_lifo_put()2.3 获取数据项k_lifo_get()3 完整应用示例3.1 中断与线程通信3.2 内存池与 LIFO 结合3.3 常见模式3.3.1 对象池模式3.3.2 批处理模式3.3.3 错误处理模式4 应用总结4.1 配置与优化4.2 应用注意点概述在 Zephyr RTOS 中LIFOs后进先出队列是与k_stack非常相似的内核对象但有一个关键区别LIFO 存储的是指针(void *)而k_stack存储的是32位数据值(stack_data_t)。这使得 LIFO 更适合传递动态分配的内存块或复杂数据结构的引用。1 LIFO 介绍1.1 核心函数列表函数功能描述主要用途k_lifo_init()初始化 LIFO动态初始化 LIFO 队列k_lifo_put()向 LIFO 添加数据项压入指针到栈顶k_lifo_get()从 LIFO 获取数据项从栈顶弹出指针K_LIFO_DEFINE()静态定义 LIFO编译时定义并初始化1.2 LIFO 的核心概念LIFO 是一个指针栈它存储的是对象的引用而不是对象本身。这意味着数据结构示例 ┌─────────────┐ ┌─────────────┐ LIFO存储的 │ 指针 0x2000│────▶│ 实际数据对象 │ 是指针 → ├─────────────┤ │ value: 42 │ │ 指针 0x3000│────▶│ value: 100 │ └─────────────┘ └─────────────┘1.3 LIFO 与其他 IPC 机制的对比特性LIFO (k_lifo)栈 (k_stack)消息队列 (k_msgq)存储内容指针(void *)32位数据值消息副本内存效率高仅存储指针高固定大小项中等复制开销数据类型任意通过指针仅 32 位值固定结构所有权传递引用需管理生命周期传递值无需管理传递副本无需管理典型用途对象池、动态数据传递简单数据栈、状态保存结构化消息传递2 核心函数详解与使用2.1 初始化 LIFO1静态初始化推荐#include zephyr/kernel.h /* 静态定义和初始化 LIFO */ K_LIFO_DEFINE(my_lifo); void example(void) { printk(LIFO 已静态初始化\n); }2动态初始化struct k_lifo my_dynamic_lifo; void init_dynamic_lifo(void) { k_lifo_init(my_dynamic_lifo); printk(LIFO 已动态初始化\n); }2.2 添加数据项k_lifo_put()1 函数原型void k_lifo_put(struct k_lifo *lifo, void *data);2参数和特征重要特性总是非阻塞立即返回线程安全可在中断中调用仅存储指针不复制数据3示例生产数据项/* 定义要传递的数据结构 */ struct sensor_data { int32_t temperature; uint32_t timestamp; uint8_t sensor_id; }; /* 生产者线程 */ void producer_thread(void) { /* 方式1传递全局/静态变量指针 */ static struct sensor_data static_data { .temperature 25, .timestamp k_uptime_get(), .sensor_id 1 }; /* 压入指向静态数据的指针 */ k_lifo_put(my_lifo, static_data); /* 方式2传递动态分配的数据需要内存管理*/ struct sensor_data *dynamic_data k_malloc(sizeof(struct sensor_data)); if (dynamic_data ! NULL) { dynamic_data-temperature 30; dynamic_data-timestamp k_uptime_get(); dynamic_data-sensor_id 2; k_lifo_put(my_lifo, dynamic_data); printk(已压入动态数据: temp%d\n, dynamic_data-temperature); } }2.3 获取数据项k_lifo_get()1 函数原型void *k_lifo_get(struct k_lifo *lifo, k_timeout_t timeout);参数说明timeout等待超时可以是K_NO_WAIT非阻塞立即返回K_FOREVER永久阻塞直到有数据时间值如K_MSEC(100)2示例消费数据项/* 消费者线程 */ void consumer_thread(void) { struct sensor_data *received_data; while (1) { /* 方式1阻塞等待数据 */ received_data k_lifo_get(my_lifo, K_FOREVER); if (received_data ! NULL) { printk(接收到: temp%d, time%u, id%u\n, received_data-temperature, received_data-timestamp, received_data-sensor_id); /* 如果是动态分配的数据使用后需要释放 */ // k_free(received_data); } /* 方式2非阻塞获取 */ // received_data k_lifo_get(my_lifo, K_NO_WAIT); // if (received_data NULL) { // k_sleep(K_MSEC(10)); /* 无数据时休眠 */ // } } }3 完整应用示例3.1 中断与线程通信#include zephyr/kernel.h #include zephyr/device.h #include zephyr/drivers/gpio.h /* 静态定义 LIFO */ K_LIFO_DEFINE(event_lifo); /* 事件数据结构 */ struct button_event { uint32_t press_count; int64_t timestamp; uint8_t button_id; }; /* 静态事件池避免动态分配*/ #define MAX_EVENTS 10 static struct button_event event_pool[MAX_EVENTS]; static int event_pool_index; /* GPIO 中断回调 */ void button_isr(const struct device *dev, struct gpio_callback *cb, uint32_t pins) { /* 从事件池获取一个事件结构简单轮询*/ struct button_event *evt event_pool[event_pool_index]; /* 更新事件数据 */ static uint32_t count 0; evt-press_count count; evt-timestamp k_uptime_get(); evt-button_id 1; /* 压入 LIFO中断中必须使用非阻塞*/ k_lifo_put(event_lifo, evt); /* 更新池索引 */ event_pool_index (event_pool_index 1) % MAX_EVENTS; } /* 事件处理线程 */ void event_handler_thread(void) { struct button_event *evt; printk(事件处理线程启动\n); while (1) { /* 阻塞等待事件 */ evt k_lifo_get(event_lifo, K_FOREVER); /* 处理事件在主线程上下文中*/ printk(按钮 %d 按下次数: %u时间: %lld ms\n, evt-button_id, evt-press_count, evt-timestamp); /* 此处可以安全执行耗时操作 */ k_sleep(K_MSEC(50)); /* 模拟处理时间 */ } }3.2 内存池与 LIFO 结合#include zephyr/kernel.h #include zephyr/sys/mempool.h /* 定义内存池 */ #define BLOCK_SIZE 64 #define NUM_BLOCKS 8 K_MEM_POOL_DEFINE(data_pool, BLOCK_SIZE, BLOCK_SIZE * NUM_BLOCKS, 4, 4); /* LIFO 用于空闲块管理 */ K_LIFO_DEFINE(free_blocks_lifo); /* 初始化空闲块池 */ void init_memory_pool(void) { for (int i 0; i NUM_BLOCKS; i) { void *block k_mem_pool_alloc(data_pool, BLOCK_SIZE, K_NO_WAIT); if (block ! NULL) { k_lifo_put(free_blocks_lifo, block); } } printk(内存池初始化完成: %d 个块\n, NUM_BLOCKS); } /* 获取一个内存块 */ void *allocate_block(k_timeout_t timeout) { /* 1. 首先尝试从 LIFO 获取空闲块 */ void *block k_lifo_get(free_blocks_lifo, K_NO_WAIT); /* 2. 如果没有空闲块从内存池分配新块 */ if (block NULL) { block k_mem_pool_alloc(data_pool, BLOCK_SIZE, timeout); } return block; } /* 释放内存块回池 */ void free_block(void *block) { if (block ! NULL) { k_lifo_put(free_blocks_lifo, block); } } /* 使用示例 */ void memory_user_thread(void) { while (1) { /* 分配内存块 */ uint8_t *data allocate_block(K_MSEC(100)); if (data ! NULL) { /* 使用内存块 */ snprintf((char *)data, BLOCK_SIZE, 数据时间戳: %lld, k_uptime_get()); printk(使用块: %s\n, data); /* 模拟处理 */ k_sleep(K_MSEC(200)); /* 释放回池 */ free_block(data); } else { printk(分配内存块失败\n); } k_sleep(K_SECONDS(1)); } }3.3 常见模式3.3.1 对象池模式/* 对象池实现 */ #define POOL_SIZE 5 struct data_object { uint32_t id; char buffer[64]; }; /* 对象池和空闲列表 */ static struct data_object object_pool[POOL_SIZE]; K_LIFO_DEFINE(free_objects); /* 初始化对象池 */ void init_object_pool(void) { for (int i 0; i POOL_SIZE; i) { object_pool[i].id i; k_lifo_put(free_objects, object_pool[i]); } } /* 获取对象 */ struct data_object *acquire_object(void) { return k_lifo_get(free_objects, K_MSEC(50)); } /* 释放对象 */ void release_object(struct data_object *obj) { if (obj ! NULL) { k_lifo_put(free_objects, obj); } }3.3.2 批处理模式/* 批处理数据收集 */ K_LIFO_DEFINE(data_batch_lifo); struct batch_data { uint32_t samples[32]; uint8_t count; uint64_t start_time; }; /* 收集线程 */ void data_collector(void) { static struct batch_data current_batch {.count 0}; while (1) { /* 收集数据 */ if (current_batch.count 32) { current_batch.samples[current_batch.count] read_sensor(); if (current_batch.count 1) { current_batch.start_time k_uptime_get(); } } /* 批次已满提交处理 */ if (current_batch.count 32) { k_lifo_put(data_batch_lifo, current_batch); /* 重置批次 */ current_batch.count 0; } k_sleep(K_MSEC(10)); } } /* 处理线程 */ void batch_processor(void) { struct batch_data *batch; while (1) { batch k_lifo_get(data_batch_lifo, K_FOREVER); printk(处理批次: %u 个样本耗时 %llu ms\n, batch-count, k_uptime_get() - batch-start_time); /* 处理批次数据... */ } }3.3.3 错误处理模式/* 安全的 LIFO 操作包装 */ void *safe_lifo_get(struct k_lifo *lifo, int max_retries) { void *data NULL; int retry 0; while (retry max_retries) { data k_lifo_get(lifo, K_MSEC(100)); if (data ! NULL) { return data; /* 成功获取 */ } retry; /* 指数退避 */ k_sleep(K_MSEC(50 * (1 (retry - 1)))); if (retry % 3 0) { printk(LIFO 获取重试: %d/%d\n, retry, max_retries); } } return NULL; /* 多次尝试失败 */ } /* 带统计的 LIFO 使用 */ #ifdef CONFIG_STATS struct lifo_stats { uint32_t puts; uint32_t gets; uint32_t timeouts; }; void monitored_lifo_put(struct k_lifo *lifo, void *data, struct lifo_stats *stats) { k_lifo_put(lifo, data); stats-puts; } void *monitored_lifo_get(struct k_lifo *lifo, k_timeout_t timeout, struct lifo_stats *stats) { void *data k_lifo_get(lifo, timeout); if (data ! NULL) { stats-gets; } else { stats-timeouts; } return data; } #endif4 应用总结4.1 配置与优化1 Kconfig 配置# 启用 LIFO 支持默认已启用 CONFIG_LIFOy # 启用内核对象追踪调试用 CONFIG_OBJECT_TRACINGy # 启用统计信息 CONFIG_KERNEL_COUNTERSy2 性能考虑/* 性能关键代码的最佳实践 */ /* 1. 避免频繁分配/释放 */ // 不佳: 频繁分配内存并压入 LIFO for (int i 0; i 1000; i) { char *buf k_malloc(100); k_lifo_put(lifo, buf); } // 更佳: 重用预分配对象 static char buffers[10][100]; for (int i 0; i 10; i) { k_lifo_put(lifo, buffers[i]); } /* 2. 使用合适的超时值 */ // 根据应用需求调整 #define FAST_RESPONSE_TIMEOUT K_MSEC(10) #define NORMAL_TIMEOUT K_MSEC(100) #define SLOW_OPERATION_TIMEOUT K_SECONDS(1) /* 3. 考虑使用无锁数据结构 */ // 对于高频操作考虑使用原子操作的自定义栈 struct lockfree_stack { atomic_t top; }; void lockfree_push(struct lockfree_stack *s, void *data) { struct node *new_node data; struct node *old_top; do { old_top atomic_get(s-top); new_node-next old_top; } while (!atomic_cas(s-top, old_top, new_node)); }4.2 应用注意点Zephyr 的 LIFO 是一个轻量级、高效的指针栈机制特别适合以下场景对象池管理重用已分配的对象减少内存碎片中断到线程通信传递事件指针避免数据复制缓冲池管理固定大小的缓冲区任务分发传递任务描述符指针1关键优势零复制仅传递指针无数据复制开销中断安全k_lifo_put可在中断中调用灵活的数据类型通过void *可传递任意数据结构2注意事项内存管理需要确保指针指向的数据在生命周期内有效空指针检查始终检查k_lifo_get的返回值并发安全虽然 LIFO 操作本身是原子的但数据内容的访问可能需要额外同步

相关新闻

如何判断网站质量低  遭受机器人流量攻击

如何判断网站质量低 遭受机器人流量攻击

做海外流量、Google SEO、独立站的人,最容易踩一个坑: 后台流量看着涨,排名和转化却一路跌。 真相往往只有两个:网站本身质量太差,或者流量被机器人污染。垃圾流量、恶意爬虫、机器刷量不仅会让你的数据完全失效&#…

2026/6/29 12:38:36 阅读更多 →
STEP3-VL-10B保姆级教程:CSDN平台WebUI访问地址动态生成逻辑与HTTPS反向代理配置

STEP3-VL-10B保姆级教程:CSDN平台WebUI访问地址动态生成逻辑与HTTPS反向代理配置

STEP3-VL-10B保姆级教程:CSDN平台WebUI访问地址动态生成逻辑与HTTPS反向代理配置 你是不是也好奇,在CSDN算力平台上部署了STEP3-VL-10B这样的多模态大模型后,那个看起来有点复杂的WebUI访问地址是怎么来的?为什么点击一下就能直接…

2026/5/17 11:29:16 阅读更多 →
【2026 计算机专业】毕业设计选题推荐:导师认可的 100多个创新题(Java方向 + 附亮点)

【2026 计算机专业】毕业设计选题推荐:导师认可的 100多个创新题(Java方向 + 附亮点)

前言2026 届计算机专业同学的毕业设计选题季已至,不少同学陷入两难:选传统管理系统怕技术栈落后,求职时没竞争力;碰 AI 类项目又担心技术难度过高,周期长且容易烂尾。本文结合 2026 年企业主流技术需求和高校答辩评审偏…

2026/5/17 11:29:15 阅读更多 →

最新新闻

庞特里亚金最大值原理 5步实战:从哈密顿函数到最优控制信号求解

庞特里亚金最大值原理 5步实战:从哈密顿函数到最优控制信号求解

庞特里亚金最大值原理 5步实战:从哈密顿函数到最优控制信号求解 引言 在工程实践中,我们常常需要设计控制系统,使其在满足各种约束条件的同时,达到某种最优性能。比如,如何让航天器以最省燃料的方式到达目标轨道&…

2026/7/6 0:23:23 阅读更多 →
DeepSeek-OCR赋能UI测试:从元素定位到视觉理解的范式转移

DeepSeek-OCR赋能UI测试:从元素定位到视觉理解的范式转移

1. 项目概述:当UI测试开始“看懂”屏幕你有没有经历过这样的崩溃时刻?团队花了整整一周,用Selenium精心编写了一套覆盖核心流程的UI自动化测试脚本,信心满满地跑回归测试。结果,前端同学只是把某个按钮的文案从“确认提…

2026/7/6 0:23:23 阅读更多 →
ResNet-50 迁移学习实战:CIFAR-10 数据集 95%+ 准确率调优(PyTorch 1.13)

ResNet-50 迁移学习实战:CIFAR-10 数据集 95%+ 准确率调优(PyTorch 1.13)

ResNet-50 迁移学习实战:CIFAR-10 数据集 95% 准确率调优指南当32x32像素的CIFAR-10图像遇上152层的深度残差网络,看似不匹配的组合却能在巧妙调优下突破95%准确率。本文将揭示如何通过迁移学习技术,让ResNet-50在这个经典数据集上展现出超越…

2026/7/6 0:23:23 阅读更多 →
PyTorch 2.0 VGG16 MNIST 实战:从原始IDX文件解析到99%+准确率模型

PyTorch 2.0 VGG16 MNIST 实战:从原始IDX文件解析到99%+准确率模型

PyTorch 2.0 VGG16 MNIST 实战:从原始IDX文件解析到99%准确率模型当谈到计算机视觉的入门任务时,MNIST手写数字识别无疑是最经典的起点。但大多数教程都停留在使用现成的torchvision.datasets加载数据,这掩盖了底层数据处理的复杂性。本文将带…

2026/7/6 0:19:22 阅读更多 →
Service Mesh 策略治理:配置多了,也会变成事故源

Service Mesh 策略治理:配置多了,也会变成事故源

Service Mesh 策略治理:配置多了,也会变成事故源 一、网格配置不是越多越安全 Service Mesh 提供流量治理、mTLS、熔断、重试、限流、镜像流量等能力。能力强是一回事,配置多是另一回事。多个 VirtualService、DestinationRule、Authorizatio…

2026/7/6 0:17:22 阅读更多 →
LSTM 时间序列预测实战:基于3000期双色球数据,构建7维序列模型

LSTM 时间序列预测实战:基于3000期双色球数据,构建7维序列模型

LSTM时间序列预测实战:基于3000期双色球数据的7维序列建模引言:当深度学习遇见概率游戏每次双色球开奖时,那些在彩票站盯着走势图沉思的身影总让人好奇——是否存在某种数学规律能穿透随机性的迷雾?作为数据科学家,我们…

2026/7/6 0:15:20 阅读更多 →

日新闻

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2与MySQL单元测试兼容性:5个关键SQL语句差异与规避方案1. 单元测试中的数据库兼容性挑战在Java开发领域,单元测试是保证代码质量的重要环节。当应用涉及数据库操作时,测试环境的搭建往往成为开发者的痛点。H2数据库因其轻量级、内存模式和快…

2026/7/6 0:01:17 阅读更多 →
Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘 【免费下载链接】rbtray A fork of RBTray from http://sourceforge.net/p/rbtray/code/. 项目地址: https://gitcode.com/gh_mirrors/rb/rbtray 你是否厌倦了Windows任务栏上密密麻麻的图标&…

2026/7/6 0:01:17 阅读更多 →
Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C 运行时库一键安装终极指南:告别DLL缺失烦恼 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾经遇到过这样的情况:下载了…

2026/7/6 0:05:19 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

月新闻