目錄
本學筆記基於zephyr 工程版本 2.2.99,主機環境爲ubuntu18.04,開發平臺 nrf52840dk_nrf52840
摘要
信號量是一個多任務系統的標配,基本上任何多任務kernel都會有信號量接口。信號多用於同步,比如ISR和線程之間的同步,由ISR釋放信號量,由線程等待信號量,這樣ISR和線程就能同步執行。
1 概念
任意數量的信號量可以被定義,每個信號量通過他的地址被引用,所以只要你的內存夠,那你就隨便定義吧。
信號量有兩個關鍵的屬性:
- 一個是count,表示信號可以被獲取(taken)的次數,當這個數是0,代表信號量無效。
- 一個是limit,表示count能達到的最大值。
信號量在使用之前北徐被初始化,他的count值在初始化的時候,可以指定一個不超過limit的非負數。
信號量可以在線程或者ISR中被釋放(given),釋放之後,如果count值不大於limit,則count值自增。
信號量可以在線程中獲取(taken),相反,獲取信號量以後count值自減,但是count值不小於0。當想要獲取的信號量無效時,線程可以選擇等待。可以有很多個線程同時等待一個相同的無效的信號量,當信號量變得有效時,最高優先級等待時間最長的線程將獲取到信號量。理論上內核允許ISR中去獲取一個信號量,但是不要在信號量無效時去等待,可以嘗試獲取,獲取不到就返回。
2 實現
2.1 定義一個信號量
使用struct k_sem類型定義一個信號量,信號量使用之前必須用k_sem_init()進行初始化。
下面的示例,定義一個信號量,設置count爲0,limit爲1:
struct k_sem my_sem;
k_sem_init(&my_sem, 0, 1);
信號量也可以使用K_SEM_DEFINE在編譯時初始化,代碼效果和上面相同:
K_SEM_DEFINE(my_sem, 0, 1);
2.2 釋放一個信號量
調用k_sem_give()釋放一個信號量。
下面示例,在中斷ISR中釋放一個信號量:
void input_data_interrupt_handler(void *arg)
{
/* notify thread that data is available */
k_sem_give(&my_sem);
...
}
2.3 獲取信號量
調用k_sem_take()獲取一個信號量。
下面的代碼,表示當獲取信號量無效時,等待50ms:
void consumer_thread(void)
{
...
if (k_sem_take(&my_sem, K_MSEC(50)) != 0) {
printk("Input data not available!");
} else {
/* fetch available data */
...
}
...
}
3 參考鏈接
https://docs.zephyrproject.org/latest/reference/kernel/synchronization/semaphores.html