信號量
概述
信號量是多任務(wù)系統(tǒng)中實現(xiàn)任務(wù)間同步,并且協(xié)調(diào)多任務(wù)對共享資源訪問的一種互斥機制。信號量允許有多個使用者,所以采用計數(shù)值來表示可用的資源數(shù),當(dāng)請求一個信號量時,該計數(shù)值減1,若此時計數(shù)值大于等于0,表示當(dāng)前有可用的信號量,則任務(wù)獲得信號量,可以訪問資源,若此時計數(shù)值為負(fù)數(shù),則任務(wù)進(jìn)入阻塞狀態(tài),釋放處理器資源。當(dāng)獲取信號量的任務(wù)執(zhí)行完操作,釋放信號量時,則將當(dāng)前計數(shù)值加1,如果當(dāng)前存在等待該資源的任務(wù),則任務(wù)被喚醒而獲得該信號量。
超時時間
信號量獲取可設(shè)置超時時間,如果任務(wù)在超時時間到期后仍未等待信號量,則任務(wù)解除阻塞進(jìn)入就緒狀態(tài)。
多任務(wù)同步
多個任務(wù)可以等待同一個信號量,若信號量可用或信號量被釋放,通常情況下,系統(tǒng)會將阻塞在該信號量上優(yōu)先級最高的任務(wù)置于就緒狀態(tài),提供了面向所有阻塞任務(wù)的信號量釋放機制,可以將阻塞在該信號量上的所有任務(wù)都置為就緒狀態(tài)。
信號量功能函數(shù)
函數(shù)名 | 描述 |
aos_sem_create() | 信號量創(chuàng)建函數(shù)(推薦),需指定計數(shù)值 |
aos_sem_new() | 信號量創(chuàng)建函數(shù)(兼容3.1),需指定計數(shù)值 |
aos_sem_free() | 信號量刪除函數(shù) |
aos_sem_wait() | 信號量獲取函數(shù),可以指定超時時間 |
aos_sem_signal() | 信號量釋放函數(shù),只喚醒阻塞在此信號量上的最高優(yōu)先級任務(wù) |
aos_sem_signal_all() | 信號量釋放函數(shù),喚醒阻塞在此信號量上的所有任務(wù) |
aos_sem_is_valid() | 判斷信號量具柄是否合法函數(shù) |
常用配置
軟件定時器功能:默認(rèn)使能,如需修改,在YAML中修改RHINO_CONFIG_SEM配置
def_config:
RHINO_CONFIG_SEM: 0
API說明
使用示例
示例代碼參考example/sem_example.c,該示例使用信號量實現(xiàn)多任務(wù)同步,具體場景為創(chuàng)建一個高優(yōu)先級任務(wù)A,一個低優(yōu)先級任務(wù)B,任務(wù)A和任務(wù)B同時等待同一信號量,此時測試任務(wù)T調(diào)用aos_sem_signal()釋放信號量,任務(wù)A首先獲得信號量,任務(wù)A操作完成后釋放一次信號量,此時任務(wù)B獲取信號量得到運行。
示例說明如下:
t0時刻,任務(wù)T調(diào)用aos_sem_create()創(chuàng)建一信號量,初始計數(shù)值為0。任務(wù)T然后調(diào)用aos_task_create()創(chuàng)建任務(wù)A和任務(wù)B,任務(wù)A優(yōu)先級為30,任務(wù)B優(yōu)先級為31。任務(wù)A和任務(wù)B運行后因等待信號量而阻塞。
t1時刻,任務(wù)T調(diào)用aos_sem_signal()釋放信號量,任務(wù)A獲得信號量。
t2時刻,任務(wù)A調(diào)用aos_sem_signal()釋放信號量,任務(wù)B獲得信號量。
該示例可配置到helloworld_demo中運行,相關(guān)代碼的下載、編譯和固件燒錄均依賴AliOS Things配套的開發(fā)工具 ,所以首先需要參考《AliOS Things集成開發(fā)環(huán)境使用說明之搭建開發(fā)環(huán)境》,下載安裝 。 待開發(fā)環(huán)境搭建完成后,可以按照以下步驟進(jìn)行示例的測試。
步驟1 創(chuàng)建或打開工程
打開已有工程
如果用于測試的案例工程已存在,可參考《AliOS Things集成開發(fā)環(huán)境使用說明之打開工程》打開已有工程。
創(chuàng)建新的工程
組件的示例代碼可以通過編譯鏈接到AliOS Things的任意案例(solution)來運行,這里選擇helloworld_demo案例。helloworld_demo案例相關(guān)的源代碼下載可參考《AliOS Things集成開發(fā)環(huán)境使用說明之創(chuàng)建工程》。
步驟2 添加組件
案例下載完成后,需要在helloworld_demo組件的package.yaml中添加對組件的依賴:
depends:
- osal_aos: dev_aos # helloworld_demo中引入osal_aos組件
步驟3 下載組件
在已安裝了的開發(fā)環(huán)境工具欄中,選擇Terminal -> New Terminal啟動終端,并且默認(rèn)工作路徑為當(dāng)前工程的workspace,此時在終端命令行中輸入:
aos install osal_aos
上述命令執(zhí)行成功后,組件源碼則被下載到了./components/osal_aos路徑中。
步驟4 添加示例
在osal_aos組件的package.yaml中添加example示例代碼:
depends:
- rhino: dev_aos
- cli: dev_aos # 添加cli依賴
source_file:
- "*.c"
- "example/sem_example.c" # 添加 sem_example.c
步驟5 編譯固件
在示例代碼已經(jīng)添加至組件的配置文件,并且helloworld_demo已添加了對該組件的依賴后,就可以編譯helloworld_demo案例來生成固件了,具體編譯方法可參考《AliOS Things集成開發(fā)環(huán)境使用說明之編譯固件》。
步驟6 燒錄固件
helloworld_demo案例的固件生成后,可參考《AliOS Things集成開發(fā)環(huán)境使用說明之燒錄固件》來燒錄固件。
步驟7 打開串口
固件燒錄完成后,可以通過串口查看示例的運行結(jié)果,打開串口的具體方法可參考《AliOS Things集成開發(fā)環(huán)境使用說明之查看日志》。
當(dāng)串口終端打開成功后,可在串口中輸入help來查看已添加的測試命令。
步驟8 測試示例
CLI命令行輸入:
sem_example
關(guān)鍵日志:
[aos_sem_example][0x34035840]field1=1449208480, field2=1449208480, field3=1449208480, field4=1449208480
[aos_sem_example][0x34035d10]field1=670588782, field2=670588782, field3=670588782, field4=670588782
[aos_sem_example][0x34035840]field1=1648917010, field2=1648917010, field3=1648917010, field4=1648917010
[aos_sem_example][0x34035d10]field1=1949034929, field2=1949034929, field3=1949034929, field4=1949034929
[aos_sem_example][0x34035840]field1=672861528, field2=672861528, field3=672861528, field4=672861528
[aos_sem_example][0x34035d10]field1=820049120, field2=820049120, field3=820049120, field4=820049120
注意事項
中斷禁止信號量獲取檢測
信號量的獲取接口在中斷上下文調(diào)用很容易發(fā)生死鎖問題。當(dāng)被打斷的上下文和打斷的中斷上下文要獲取同一個信號量時,會發(fā)生互相等待的情況。有些內(nèi)核將這種判斷處理交由上層軟件進(jìn)行判斷和使用,本內(nèi)核會在take信號量檢測,如果是中斷上下文,則直接返回失敗。
占用信號量非等待、永遠(yuǎn)等待、延時使用區(qū)別
應(yīng)用程序在獲取信號量時,需要按照實際的需求,來安排信號量獲取策略。aos_sem_take傳入延時timeout為0,獲取不到信號量會立即報失敗;timeout為AOS_WAIT_FOREVER時,會永遠(yuǎn)在此等待,直到獲取到信號量,可能會造成該任務(wù)無法繼續(xù)運行;其他值標(biāo)識最大延遲的時間上限,達(dá)到上限時,即使未獲取到信號量,任務(wù)也會被喚醒,并返回錯誤。
FAQ
Q1: 調(diào)用aos_sem_task()接口無限期的等待信號量,timeout參數(shù)怎么設(shè)置? 答:將timeout賦值為AOS_WAIT_FOREVER。