栈
栈 是实现传统后进先出(LIFO)队列的内核对象,允许线程和 ISR 添加或移除有限数量的整数数据值。
概念
可以定义任意数量的栈(仅受可用 RAM 限制)。每个栈都通过其内存地址引用。
栈具有以下主要属性:
一个 队列,存放已添加但尚未移除的整数数据值。队列使用 stack_data_t 类型的数组实现,必须按本机字边界对齐。stack_data_t 类型的大小与本机字长相同,即根据 CPU 架构和编译模式为 32 位或 64 位。
数组中可存放数据值的 最大数量。
栈必须初始化后才能使用。初始化会将其队列置空。
线程或 ISR 均可向栈 添加 数据值。如果有线程正在等待,则直接将数据值交给该线程;否则将其加入 LIFO 队列。
备注
如果启用了 CONFIG_NO_RUNTIME_CHECKS,内核 不会 检测和阻止向已达到容量上限的栈添加数据值的尝试。向已满的栈添加数据值会导致数组溢出,进而产生不可预测的行为。
线程可以从栈 移除 数据值。如果栈的队列为空,线程可以选择等待数据值到来。任意数量的线程都可以同时等待一个空栈。添加数据项后,它会被交给优先级最高且等待时间最长的线程。
备注
内核允许 ISR 从栈移除数据项,但栈为空时,ISR 不得尝试等待。
实现
定义栈
栈使用 k_stack 类型的变量定义,随后必须调用 k_stack_init() 或 k_stack_alloc_init() 进行初始化。使用后者时无需提供缓冲区,缓冲区会从调用线程的资源池中分配。
以下代码定义并初始化一个空栈,最多可容纳十个字大小的数据值。
#define MAX_ITEMS 10
stack_data_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);
入栈
调用 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, (stack_data_t)&my_buffers[i]);
}
出栈
调用 k_stack_pop() 可以从栈取出数据项。
以下代码延续上面的示例,展示线程如何动态分配一个尚未使用的数据结构。当不再需要该数据结构时,线程必须将其地址重新压入栈,以便复用。
struct my_buffer_type *new_buffer;
k_stack_pop(&buffer_stack, (stack_data_t *)&new_buffer, K_FOREVER);
new_buffer->field1 = ...
使用建议
如果已知最多需要存储多少个数据项,可以使用栈以“后进先出”的方式存取整数数据值。
配置选项
相关配置选项:
无。