# 任務與協程 ## 區別 > 一個程式可以只有任務、只有協程、二者都有,但不可以通過隊列/信號量互相傳遞數據 ## 任務特點 1. 任務之間可以互相獨立 2. 每個任務分配自己的堆棧,提高了RAM使用率 3. 操作簡單、按優先順序搶占式執行 4. 搶占容易導致重入(執行任務時被其他線程或進程調用了) ...
任務與協程
區別
一個程式可以只有任務、只有協程、二者都有,但不可以通過隊列/信號量互相傳遞數據
任務特點
-
任務之間可以互相獨立
-
每個任務分配自己的堆棧,提高了RAM使用率
-
操作簡單、按優先順序搶占式執行
-
搶占容易導致重入(執行任務時被其他線程或進程調用了)
協程特點
-
一般用於小型,RAM有限制的處理器上
-
所有協程共用一個堆棧
-
通過一組巨集實現的
-
減少了重入問題,但是和任務混用總搶不過人家
任務狀態
運行、就緒、阻塞、掛起
任務優先順序
-
0--configMAX_PRIORITIES - 1,最大值定義在FreeRTOSConfig.h中
-
設置的越小越好,某些特殊情況不得超過32
-
空閑任務優先順序為0
-
預設情況,相同優先順序按時間切片輪流運行
任務調度
單核調度
-
搶占式調度,即使在同一時間片,出現了一個高優先順序任務,也會打斷當前的低優先順序任務。
-
時間片指兩個tick中斷之間的時間,相同優先順序的任務,一人一個時間片依次執行。
-
如果一個高優先順序任務永遠不阻塞、不掛起,低優先順序任務永遠也不會執行,因此推薦創建事件驅動的任務,等待事件的時候阻塞掉它,收到事件再解除阻塞
-
高優先順序任務處於“阻塞”狀態時, 低優先順序任務會運行。
-
FreeRTOSConfig中:
configUSE_PREEMPTION=0
關閉搶占,只有阻塞/掛起/運行的任務調用 taskYIELD()/ISR才會切換下文的任務
configUSE_TIME_SLICING=0
關閉時間片,相同優先順序的任務不會在tick間隔後切換。
AMP調度
非對稱多核處理,每個核心獨立運行位元組的實例,不需要有相同架構
SMP調度
對稱多核處理,一個程式跨多個處理器調度
- 單核移植到SMP
-
configRUN_MULTIPLE_PRIORITIES = 0 ,可以同時運行優先順序相同的多個任務
-
configUSE_CORE_AFFINITY = 1,通過vTaskCoreAffinitySet() 方法定義某個任務可以在哪個核運行
任務實現
定義任務
void vMyTask(void *pvParameters)
{
for(;;){
Task coding here...
//任務代碼寫在死迴圈里,非必要不退出,退出一定要delete
}
vTaskDelete(NULL);
}
typedef void (*TaskFunction_t)(void*);
-
這句話是什麼意思呢,就是TaskFunction_t是一個指向函數的指針,這類函數具有void * 類型的形參,返回值類型是void
-
事件型驅動代碼框架,WaitForEvent是消息隊列接收/事件等待等
if(WaitForEvent(事件,等待超時時間))
{Tasking coding here...}
else
{報錯、處理錯誤等}
- 通過巨集定義實現一個任務定義
portTASK_FUNCTION_PROTO( vMyTask, pvParameters );
隊列
隊列是任務間通信的主要形式,先入先出
-
數據被拷貝到隊列中,而不是傳地址
-
讀空隊列、寫入滿隊列都會導致阻塞,高優先順序的優先解除阻塞
-
隊列API允許指定阻塞最長時間,
信號量
是一種實現任務間通信的機制,是一個計數器
每當有個任務獲取信號量計數器就減一,變成0後所有試圖獲取信號量的任務都阻塞了
信號量當前的值就是可用資源數,
二值信號量
許多情況下可以用任務通知代替二值信號量
-
信號量API允許指定最大阻塞時間,阻塞時間指的是tick間隔的數量
-
二進位信號量可視為容量為1的隊列
用處
一個任務只用來服務一個外設,但不是一直服務的,還有輪詢或者其他無關操作,這時候就可以用二值信號量減少資源浪費。
具體操作為:
-
任務執行時獲取信號量,所謂獲取信號量就是讓計數器-1,變成0了,於是進入阻塞狀態,其他任務想執行就可以執行
-
當外設需要任務了,就觸發中斷給出信號量,也就是變成1了,原來的任務不阻塞了,繼續為外設服務。
-
我覺得可以理解成把主動權交給外設,需要任務就叫他
計數信號量
長度大於1的隊列
用處
-
初始定義信號量為0,用來盤點事件,發生一個事件+1,處理後-1
-
初始定義信號量為MAX,用於資源管理,每執行一次任務減一
互斥鎖
互斥鎖是包含優先順序繼承機制的二進位信號量
在 FreeRTOS 中,通常採用搶占式調度。這意味著當一個高優先順序任務準備好並且具備運行條件時,它會立即搶占當前正在執行的低優先順序任務。
然而,即使是搶占式調度,仍然可能出現低優先順序任務占用資源導致高優先順序任務無法執行的情況,原因就是高優先順序任務沒有準備好
-
互斥鎖之所以叫互斥,是因為它執行當前的任務時把他優先順序調到最高了,就算浪費資源也要先把它執行完
-
不要在中斷中使用互斥鎖,因為中斷無法保持阻塞等待互斥鎖的任務執行完畢,而且優先順序繼承機制要求從任務中拿出而不是中斷中
遞歸互斥鎖
只有一個任務成功執行n次(遞歸深度)才可以解鎖
任務通知
每個任務都有一個任務通知數組,數組裡每條通知都有掛起、不掛起倆狀態和一個32位通知值
-
configTASK_NOTIFICATION_ARRAY_ENTRIES 設置任務通知數組最大索引
-
直達任務通知是直接發到任務的通知
-
任務可以被通知阻塞,等待通知下達掛起指令