目錄
本學筆記基於zephyr 工程版本 2.2.99,主機環境爲ubuntu18.04,開發平臺 nrf52840dk_nrf52840
摘要
LIFO是一個內核對象,實現了傳統的後進先出(last in, first out)隊列,允許線程和ISR添加或者移除任意大小的數據項。
1 概念
任意數量的LIFO可以被定義。引用lifo時,使用的是LIFO定義的內存地址,同樣只要你的內存允許,就可以隨便定義。
LIFO有如下關鍵屬性:
一個queue,他存儲已經被添加但是還沒有被移除的數據項。這個queue是用簡單的鏈表實現的(實際上就是一個由鏈表實現的隊列)。LIFO的功能是基於這個後進先出的queue實現的,LIFO就相當於queue的head。
一個LIFO必須先初始化在使用,初始化設置這個隊列爲空。
LIFO的數據項對必須保持字(word,cortext-M是4字節)對齊,這個數據項的第一個字節被內核使用,用於存儲在queue中下一個數據項的內存地址。因此,一個有N字節應用數據的數據項,需要佔用N+4(or N+8, 64位系統中word是8字節)內存空間。如果使用k_lifo_alloc_put()個函數添加一個數據項到一個隊列,就不需要指向下一個地址的保留word。因爲這個函數會從線程的資源池中分配臨時的內存用於存儲下一個數據項的地址。
一個數據項可以被ISR或者線程添加,如果有正在等待數據項的線程(就是讀取隊列,隊列中沒有數據項,線程休眠了),那麼添加一個數據項之後,數據項不被添加到LIFO的quue中,而是直接給等待的線程。也就是數據項不是由發送線程存儲到LIFO的queue中,然後再由等在線程從queue中取出。而是直接從發送線程傳給因爲接收而等待的線程,不會經過queue的。相反,如果沒有等待的接收線程,那麼纔會添加數據項到LIFO的queue。
一個數據可以被一個線程移除(也就是取出),如果LIFO中沒有數據元素,那麼線程可以選擇等待LIFO不爲空(就是說線程獲取不到LIFO進入睡眠,當LIFO不爲空的時候再喚醒)。可以有多個線程同時等待一個空的LIFO。當有數據項添加到LIFO中,那個優先級最高等待時間最長的線程,會優先喚醒去讀取數據。
2 實現
2.1 定義LIFO
使用struct k_lifo類型定義一個LIFO變量。使用之前必須用k_lifo_init()進行初始化:
struct k_lifo my_lifo;
k_lifo_init(&my_lifo);
或者,在編譯時使用K_LIFO_DEFINE宏定義和初始化一個LIFO:
K_LIFO_DEFINE(my_lifo);
2.2 寫數據項到LIFO
可以調用k_lifo_put()函數,向LIFO中添加一個數據項。
下面的示例發送數據到一個或多個用戶線程:
struct data_item_t {
void *lifo_reserved; /* 1st word reserved for use by lifo */
...
};
struct data_item_t tx_data;
void producer_thread(int unused1, int unused2, int unused3)
{
while (1) {
/* create data item to send */
tx_data = ...
/* send data to consumers */
k_lifo_put(&my_lifo, &tx_data);
...
}
}
也可以使用k_lifo_alloc_put()函數添加,那麼添加的數據項內存中第一個word也是有效的,不會被內核佔中。
2.3 從LIFO中讀數據
可以調用k_lifo_get()從LIFO中讀取一個數據項:
void consumer_thread(int unused1, int unused2, int unused3)
{
struct data_item_t *rx_data;
while (1) {
rx_data = k_lifo_get(&my_lifo, K_FOREVER);
/* process lifo data item */
...
}
}
3 參考鏈接
https://docs.zephyrproject.org/latest/reference/kernel/data_passing/lifos.html