重要概念
在運行的任務,被稱為"正在使用處理器",它處于運行狀態。在單處理系統中,任何時間里只能有一個任務處于運行狀態。
非運行狀態的任務,它處于這 3 中狀態之一:阻塞(Blocked)、暫停(Suspended)、就緒(Ready)。
就緒態的任務,可以被調度器挑選出來切換為運行狀態,調度器永遠都是挑選最高優先級的就緒態任務并讓它進入運行狀態。
阻塞狀態的任務,它在等待"事件",當事件發生時任務就會進入就緒狀態。
事件分為兩類:時間相關的事件、同步事件。
所謂時間相關的事件,就是設置超時時間:在指定時間內阻塞,時間到了就進入就緒狀態。使用時間相關的事件,可以實現周期性的功能、可以實現超時功能。
同步事件就是:某個任務在等待某些信息,別的任務或者中斷服務程序會給它發送信息。怎么"發送信息"?方法很多,有:任務通知(task notification)、隊列(queue)、事件組(event group)、信號量(semaphoe)、互斥量(mutex)等。這些方法用來發送同步信息,比如表示某個外設得到了數據。
配置調度算法
所謂調度算法,就是怎么確定哪個就緒態的任務可以切換為運行狀態。
通 過 配 置 文 件 FreeRTOSConfig.h 的 兩 個 配 置 項 來 配 置 調 度 算 法 :
- configUSE_PREEMPTION、
- configUSE_TIME_SLICING。
- configUSE_TICKLESS_IDLE,它是一個高級選項,用于關閉 Tick中斷來實現省電,后續單獨講解。 現在configUSE_TICKLESS_IDLE 設為 0,先不使用這個功能。
調度算法的行為主要體現在兩方面:高優先級的任務先運行、同優先級的就緒態任務如何被選中。調度算法要確保同優先級的就緒態任務,能"輪流"運行,策略是"輪轉調度"(Round Robin Scheduling)。輪轉調度并不保證任務的運行時間是公平分配的,我們還可以細化時間的分配方法。
從 3 個角度統一理解多種調度算法:
- 可否搶占?高優先級的任務能否優先執行(配置項: configUSE_PREEMPTION)
- 可以:被稱作"可搶占調度"(Pre-emptive),高優先級的就緒任務馬上執行,下面再細化。
- 不可以:不能搶就只能協商了,被稱作"合作調度模式"(Co-operativeScheduling) ,這種模式下:當前任務執行時,更高優先級的任務就緒了也不能馬上運行,只能等待當前任務主動讓出 CPU 資源。 其他同優先級的任務也只能等待(更高優先級的任務都不能搶占,平級的更應該老實點)。
- 可搶占的前提下,同優先級的任務是否輪流執行(配置configUSE_TIME_SLICING)
- 輪流執行:被稱為"時間片輪轉"(Time Slicing),同優先級的任務輪流執行,你執行一個時間片、我再執行一個時間片
- 不輪流執行:英文為"without Time Slicing",當前任務會一直執行,直到主動放棄、或者被高優先級任務搶占。(如果任務1一直執行直到高任務搶占,高任務放棄執行時候,就會執行任務1同級別的其他任務了)
- 在"可搶占"+"時間片輪轉"的前提下,進一步細化:空閑任務是否讓步于用戶任務(配置項: configIDLE_SHOULD_YIELD)
- 空閑任務低人一等,每執行一次循環,就看看是否主動讓位給用戶任務
- 空閑任務跟用戶任務一樣,大家輪流執行,沒有誰更特殊。
以下是整理后的 Markdown 表格格式:
配置項 | A (常用) | B (很少用) | C (很少用) | D (很少用) | E (幾乎不用) |
---|---|---|---|---|---|
模式 | 可搶占+時間片輪轉+空閑任務讓步 | 可搶占+時間片輪轉+空閑任務不讓步 | 可搶占+非時間片輪轉+空閑任務讓步 | 可搶占+非時間片輪轉+空閑任務不讓步 | 合作調度 |
configUSE_PREEMPTION | 1 | 1 | 1 | 1 | 0 |
configUSE_TIME_SLICING | 1 | 1 | 0 | 0 | x |
configIDLE_SHOULD_YIELD | 1 | 0 | 1 | 0 | x |