1 前言
堆栈是实现传统的后进先出 (LIFO) 队列的内核对象,允许线程和ISR添加和移除有限数量的32位数据值。
我正在学习 Zephyr,一个很可能会用到很多物联网设备上的操作系统,如果你也感兴趣,可点此查看帖子zephyr学习笔记汇总。
2 概念
可以定义任何数量的堆栈,每个堆栈都由其内存地址引用。
堆栈具有以下关键属性:
- 已添加但尚未删除的32位数据值的队列。队列使用32位整数数组实现,并且必须在4字节边界上对齐。
- 可在数组中排队的最大数量的数据值。
堆栈必须在可以使用之前进行初始化。这将其队列设置为空。
数据值可以通过线程或ISR添加到堆栈。该值直接给予等待的线程(如果存在的话); 否则该值将被添加到lifo的队列中。 内核不会检测将数据值添加到已达到其最大数量的排队值的堆栈的尝试。
注意:将数据值添加到已满的堆栈会导致数组溢出,并导致不可预知的行为。
数据值可以由线程从堆栈中移除。如果堆栈的队列是空的,则线程可以选择等待它给出。任何数量的线程可能会同时等待一个空的堆栈。 当数据项被添加时,它被赋予等待时间最长的最高优先级线程。
注意:内核确实允许ISR从堆栈中移除一个项目,但是如果堆栈为空,则ISR不能尝试等待。
3 操作
3.1 定义堆栈
堆栈是使用 struct k_stack 类型的变量定义的。它必须通过调用 k_stack_init() 来初始化。
以下代码定义并初始化一个能够保存最多10个32位数据值的空堆栈。
#define MAX_ITEMS 10
u32_t my_stack_array[MAX_ITEMS];
struct k_stack my_stack;
k_stack_init(&my_stack, my_stack_array, MAX_ITEMS);
或者,可以在编译时通过调用 K_STACK_DEFINE 来定义和初始化堆栈。
以下代码与上面的代码段具有相同的效果。 观察宏定义了堆栈及其数组值。
K_STACK_DEFINE(my_stack, MAX_ITEMS);
3.2 推入堆栈
通过调用 k_stack_push() 将数据项添加到堆栈中。
以下代码构建在上面的示例上,并显示了线程如何通过将其内存地址保存在堆栈中来创建数据结构池。
/* define array of data structures */
struct my_buffer_type {
int field1;
...
};
struct my_buffer_type my_buffers[MAX_ITEMS];
/* save address of each data structure in a stack */
for (int i = 0; i < MAX_ITEMS; i++) {
k_stack_push(&my_stack, (u32_t)&my_buffers[i]);
}
3.3 从堆栈弹出
通过调用 k_stack_pop() 从数据栈中获取数据项。
以下代码构建在上述示例上,并显示了线程如何动态分配未使用的数据结构。当不再需要数据结构时,线程必须将其地址重新放回堆栈以允许重新使用数据结构。
struct my_buffer_type *new_buffer;
k_stack_pop(&buffer_stack, (u32_t *)&new_buffer, K_FOREVER);
new_buffer->field1 = ...
4 建议用法
当已知存储项目的最大数量时,使用堆栈以“后进先出”方式存储和检索32位数据值。
5 配置选项
无
6 APIs
下列栈的API,都在 kernel.h 中提供了:
K_STACK_DEFINE
k_stack_init()
k_stack_push()
k_stack_pop()