目录
本学笔记基于zephyr 工程版本 2.2.99,主机环境为ubuntu18.04,开发平台 nrf52840dk_nrf52840
摘要
stack是一个内核对象,它实现了后进先出队列( last in, first out),允许线程和ISR添加或移除有限个整数值。
1 概念
任意个数的stack可以被定义,引用Stack时,使用的是Stack定义的内存地址,同样只要你的内存允许,就可以随便定义。
Stack有下面关键属性:
一个整数值的queue,用于存储加入Stack并且还没有被移除的数据项。queue是通过stack_data_t类型值得一个数组来实现的,并且必须是字对齐。stack_data_t类型和cpu的word大小是一致的,一般是4个字节或者8个字节。
maximum quantity 加入队列数组的数值的最大个数。
stack使用之前必须被初始化,初始化会将queue设置为空。
一个数据值可以被ISR或者线程添加到stack,如果有等待线程存在,这个值会直接的传给线程,而不是先加入queue再取出然后再给等待的线程。其他情况这个值会被添加到LIFO类型的queue。当stack中的队列达到最大值,如果再继续向stack中添加数据项,内核是不去检测的。将导致一个未定义的行为。类似于栈溢出了。
一个数据向可以被线程移除(取出),如果线程从一个没有数据项的stack中取数据,那么线程会进入等待,直到有数据项可以从stack中读出。多个线程可以同时的访问一个空的stack,当有数据项添加到stack中,优先级最高,等待时间最长的线程将先获得数据项。
内核也允许在isr中去取出stack中的数据项,但是stack为控制,isr不要尝试去等待。
2 实现
2.1 定义一个stack
使用struct k_stack类型去定义stack变量,k_stack_init()或者k_stack_alloc_init()去初始化这个stack。使用这个k_stack_alloc_init()函数初始化的时候,一个缓冲区不用被提供,缓冲区可以的从线程内存池中分配。
下面代码,定义并初始化一个可以保存10个数据的空stack:
#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);
2.2 入栈
可以调用k_stack_push()函数,添加一个数据项到stack。
下面的示例展示,定义一个数据结构内存池,并且将他们的地址加入到stack中:
/* 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]);
}
2.3 出栈
可以调用k_stack_pop()函数,将数据项从stack中取出:
下面的示例展示了,一个线程动态的分配一个没有使用的数据结构,当这个数据结构不在被需要,这个线程应该将这个数据结构的地址重新入栈:
struct my_buffer_type *new_buffer;
k_stack_pop(&buffer_stack, (stack_data_t *)&new_buffer, K_FOREVER);
new_buffer->field1 = ...
3 参考链接
https://docs.zephyrproject.org/latest/reference/kernel/data_passing/stacks.html