1、二值信號量
二值信號量通常用于互斥訪問或同步,二值信號量和互斥信號量非常類似,但是還是有一些細(xì)微的差別,互斥信號量擁有優(yōu)先級繼承機(jī)制,二值信號量沒有優(yōu)先級繼承。因此二值信號量更適合用于同步(任務(wù)與任務(wù)或任務(wù)與中斷的同步),而互斥信號量適合用于簡單的互斥訪問。
和隊列一樣,信號量 API 函數(shù)允許設(shè)置一個阻塞時間,阻塞時間是當(dāng)任務(wù)獲取信號量的時候由于信號量無效從而導(dǎo)致任務(wù)進(jìn)入阻塞態(tài)的最大時鐘節(jié)拍數(shù)。如果多個任務(wù)同時阻塞在同一個信號量上的話那么優(yōu)先級最高的哪個任務(wù)優(yōu)先獲得信號量,這樣當(dāng)信號量有效的時候高優(yōu)先級的任務(wù)就會解除阻塞狀態(tài)。
二值信號量其實就是一個只有一個隊列項的隊列,這個特殊的隊列要么是滿的,要么是空的,這不正好就是二值的嗎?任務(wù)和中斷使用這個特殊隊列不用在乎隊列中存的是什么消息,只需要知道這個隊列是滿的還是空的。可以利用這個機(jī)制來完成任務(wù)與中斷之間的同步。
在實際應(yīng)用中通常會使用一個任務(wù)來處理 MCU 的某個外設(shè),比如網(wǎng)絡(luò)應(yīng)用中,一般最簡單的方法就是使用一個任務(wù)去輪詢的查詢 MCU 的 ETH 外設(shè)是否有數(shù)據(jù),當(dāng)有數(shù)據(jù)的時候就處理這個網(wǎng)絡(luò)數(shù)據(jù)。這樣使用輪詢的方式是很浪費(fèi)CPU 資源的,而且也阻止了其他任務(wù)的運(yùn)行。最理想的方法就是當(dāng)沒有網(wǎng)絡(luò)數(shù)據(jù)的時候網(wǎng)絡(luò)任務(wù)就進(jìn)入阻塞態(tài),把 CPU 讓給其他的任務(wù),當(dāng)有數(shù)據(jù)的時候網(wǎng)絡(luò)任務(wù)才去執(zhí)行。現(xiàn)在使用二值信號量就可以實現(xiàn)這樣的功能,任務(wù)通過獲取信號量來判斷是否有網(wǎng)絡(luò)數(shù)據(jù),沒有的話就進(jìn)入阻塞態(tài),而網(wǎng)絡(luò)中斷服務(wù)函數(shù)通過釋放信號量來通知任務(wù)以太網(wǎng)外設(shè)接收到了網(wǎng)絡(luò)數(shù)據(jù),網(wǎng)絡(luò)任務(wù)可以去提取處理了。網(wǎng)絡(luò)任務(wù)只是在一直的獲取二值信號量,它不會釋放信號量,而中斷服務(wù)函數(shù)是一直在釋放信號量,它不會獲取信號量。在中斷服務(wù)函數(shù)中發(fā)送信號量可以使用函數(shù) xSemaphoreGiveFromISR()。
2、計數(shù)型信號量
有些資料中也將計數(shù)型信號量叫做數(shù)值信號量,二值信號量相當(dāng)于長度為 1 的隊列,那么計數(shù)型信號量就是長度大于 1 的隊列。同二值信號量一樣,用戶不需要關(guān)心隊列中存儲了什么數(shù)據(jù),只需要關(guān)心隊列是否為空即可。計數(shù)型信號量通常用于如下兩個場合:
事件計數(shù)
在這個場合中,每次事件發(fā)生的時候就在事件處理函數(shù)中釋放信號量(增加信號量的計數(shù)值),其他任務(wù)會獲取信號量(信號量計數(shù)值減一,信號量值就是隊列結(jié)構(gòu)體成員變量uxMessagesWaiting)來處理事件。在這種場合中創(chuàng)建的計數(shù)型信號量初始計數(shù)值為 0。
資源管理
在這個場合中,信號量值代表當(dāng)前資源的可用數(shù)量,比如停車場當(dāng)前剩余的停車位數(shù)量。一個任務(wù)要想獲得資源的使用權(quán),首先必須獲取信號量,信號量獲取成功以后信號量值就會減一。當(dāng)信號量值為 0 的時候說明沒有資源了。當(dāng)一個任務(wù)使用完資源以后一定要釋放信號量,釋放信號量以后信號量值會加一。在這個場合中創(chuàng)建的計數(shù)型信號量初始值應(yīng)該是資源的數(shù)量,比如停車場一共有 100 個停車位,那么創(chuàng)建信號量的時候信號量值就應(yīng)該初始化為 100。
3、互斥信號量
互斥信號量其實就是一個擁有優(yōu)先級繼承的二值信號量,在同步的應(yīng)用中(任務(wù)與任務(wù)或中斷與任務(wù)之間的同步)二值信號量最適合。互斥信號量適合用于那些需要互斥訪問的應(yīng)用中。在互斥訪問中互斥信號量相當(dāng)于一個鑰匙,當(dāng)任務(wù)想要使用資源的時候就必須先獲得這個鑰匙,當(dāng)使用完資源以后就必須歸還這個鑰匙,這樣其他的任務(wù)就可以拿著這個鑰匙去使用資源。
互斥信號量使用和二值信號量相同的 API 操作函數(shù),所以互斥信號量也可以設(shè)置阻塞時間,不同于二值信號量的是互斥信號量具有優(yōu)先級繼承的特性。當(dāng)一個互斥信號量正在被一個低優(yōu)先級的任務(wù)使用,而此時有個高優(yōu)先級的任務(wù)也嘗試獲取這個互斥信號量的話就會被阻塞。不過這個高優(yōu)先級的任務(wù)會將低優(yōu)先級任務(wù)的優(yōu)先級提升到與自己相同的優(yōu)先級,這個過程就是優(yōu)先級繼承。優(yōu)先級繼承盡可能的降低了高優(yōu)先級任務(wù)處于阻塞態(tài)的時間,并且將已經(jīng)出現(xiàn)的“優(yōu)先級翻轉(zhuǎn)”的影響降到最低。
優(yōu)先級繼承并不能完全的消除優(yōu)先級翻轉(zhuǎn),它只是盡可能的降低優(yōu)先級翻轉(zhuǎn)帶來的影響。硬實時應(yīng)用應(yīng)該在設(shè)計之初就要避免優(yōu)先級翻轉(zhuǎn)的發(fā)生。互斥信號量不能用于中斷服務(wù)函數(shù)中,原因如下:
● 互斥信號量有優(yōu)先級繼承的機(jī)制,所以只能用在任務(wù)中,不能用于中斷服務(wù)函數(shù)。
● 中斷服務(wù)函數(shù)中不能因為要等待互斥信號量而設(shè)置阻塞時間進(jìn)入阻塞態(tài)。
4、遞歸互斥信號量
遞歸互斥信號量可以看作是一個特殊的互斥信號量,已經(jīng)獲取了互斥信號量的任務(wù)就不能再次獲取這個互斥信號量,但是遞歸互斥信號量不同,已經(jīng)獲取了遞歸互斥信號量的任務(wù)可以再次獲取這個遞歸互斥信號量,而且次數(shù)不限!一個任務(wù)使用函數(shù) xSemaphoreTakeRecursive()成功的獲取了多少次遞歸互斥信號量就得使用函數(shù) xSemaphoreGiveRecursive()釋放多少次!比如某個任務(wù)成功的獲取了 5 次遞歸信號量,那么這個任務(wù)也得同樣的釋放 5 次遞歸信號量。
遞歸互斥信號量也有優(yōu)先級繼承的機(jī)制,所以當(dāng)任務(wù)使用完遞歸互斥信號量以后一定要記得釋放。同互斥信號量一樣,遞歸互斥信號量不能用在中斷服務(wù)函數(shù)中。
● 由于優(yōu)先級繼承的存在,就限定了遞歸互斥信號量只能用在任務(wù)中,不能用在中斷服務(wù)函數(shù)中!
● 中斷服務(wù)函數(shù)不能設(shè)置阻塞時間。
要使用遞歸互斥信號量的話宏 configUSE_RECURSIVE_MUTEXES 必須為 1!
-
嵌入式
+關(guān)注
關(guān)注
5092文章
19177瀏覽量
307647 -
信號
+關(guān)注
關(guān)注
11文章
2804瀏覽量
77099 -
FreeRTOS
+關(guān)注
關(guān)注
12文章
484瀏覽量
62394
發(fā)布評論請先 登錄
相關(guān)推薦
評論