目录概述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 操作本身是原子的但数据内容的访问可能需要额外同步