概要
スケジューラ(Scheduler)は、RTOS(リアルタイムオペレーティングシステム)のカーネルの中核となるコンポーネントで、複数のタスク(スレッド)の中からどれをCPUで実行するかを決定し、切り替える仕組みです。
スケジューラの役割は単に「次に実行するタスクを選ぶ」だけでなく、以下を含みます。
- タスクの状態管理(実行可能・待機・ブロック・停止)
- 優先度の管理とプリエンプション(実行中タスクの強制中断)
- コンテキストスイッチの実行(レジスタ・スタックポインタの保存・復元)
- タイマ管理(タイムスライス、
vTaskDelay等の時間待機)
適切なスケジューリングアルゴリズムと設定により、ハードリアルタイム要件を満たすシステムを構築できます。
歴史・背景
スケジューリング理論の基礎は1960〜70年代のOS研究から始まりました。最も重要な理論的成果の一つが、1973年にC.L.LiuとJ.W.Laylandが発表した「Scheduling Algorithms for Multiprogramming in a Hard-Real-Time Environment」です。この論文でレートモノトニック(RM)スケジューリングの最適性と、CPUユーティリゼーションの上限(n→∞で約69.3%)が証明されました。
1980年代の商用RTOS(VxWorks等)は優先度ベースのプリエンプティブスケジューラを採用し、リアルタイムシステムの実用化を加速しました。
Linuxカーネルのスケジューラも進化を続けており、2007年にLinux 2.6.23で採用された**CFS(Completely Fair Scheduler)**は公平性重視の設計です。リアルタイム向けにはSCHED_FIFO/SCHED_RRポリシーが別途用意されており、PREEMPT_RTパッチにより割り込みレイテンシをさらに低減できます。
技術仕様
スケジューリングアルゴリズムの種類
| アルゴリズム | 優先度割り当て | 特徴 | 代表的な用途 |
|---|---|---|---|
| レートモノトニック(RM) | 静的(周期短い順) | 最適性証明あり・分析容易 | ハードリアルタイム |
| EDF(Earliest Deadline First) | 動的(締切早い順) | 利用率100%まで最適・実装複雑 | 理論研究・一部RTOS |
| 優先度ベースFIFO(SCHED_FIFO) | 静的・手動設定 | 同優先度内は実行順 | FreeRTOS・VxWorks |
| ラウンドロビン(SCHED_RR) | 静的+タイムスライス | 同優先度でタイムスライス | Linux POSIX RT |
| CFS(Completely Fair Scheduler) | 動的・仮想ランタイム | 公平性重視・スループット最大 | Linuxデスクトップ |
FreeRTOSスケジューラの仕様
| 設定 | デフォルト値 | 説明 |
|---|---|---|
configMAX_PRIORITIES | 5(設定可能) | タスク優先度の最大段階数 |
configTICK_RATE_HZ | 1000 | スケジューラTick周波数(1ms Tick) |
configUSE_PREEMPTION | 1 | プリエンプティブスケジューリング有効 |
configUSE_TIME_SLICING | 1 | 同優先度タスク間のラウンドロビン有効 |
configIDLE_TASK_STACK_SIZE | 128ワード | アイドルタスクのスタック |
スケジューラのTick割り込み
RTOSはハードウェアタイマを使ってTick割り込みを定期発生させます。Tick割り込みごとに:
- タイマ待機中のタスクのカウントダウン
- タイムスライスの管理
- 優先度の高いタスクが実行可能になった場合のプリエンプション要求
FreeRTOSのデフォルトでは1ms Tick(configTICK_RATE_HZ=1000)ですが、レイテンシ要件に応じて変更します。
動作原理
優先度ベーススケジューリングの動作例
タスク優先度設定:
TaskA: 優先度3(高) - センサ読み取り
TaskB: 優先度2(中) - データ処理
TaskC: 優先度1(低) - ログ記録
動作シナリオ:
時刻0ms: スケジューラ起動 → TaskAが実行可能 → TaskA実行開始
時刻5ms: TaskAがvTaskDelay(95ms)でブロック → TaskBへコンテキストスイッチ
時刻20ms: TaskBがキュー待機でブロック → TaskCへ
時刻100ms: TaskAのタイマ満了 → 即座にTaskCを中断(プリエンプション)→ TaskA実行
スケジューラの実装原理
スケジューラのコアは「ready リスト」の管理です。FreeRTOSでは優先度ごとにリスト(連結リスト)を持ち、実行可能な最高優先度タスクを選択します。
Ready List(概念):
優先度3: [TaskA] ← 次に実行するタスク
優先度2: [TaskB, TaskD]
優先度1: [TaskC]
優先度0: [IdleTask]
Blocked List(待機中タスク):
- TaskX: 残り50ms でReadyへ移動
- TaskY: キューに要素が来るまで待機
コンテキストスイッチのタイミング
スケジューラがコンテキストスイッチを実行するタイミング:
- タスクがブロック状態へ移行:
vTaskDelay()、xQueueReceive()(ブロッキング)等 - Tick割り込み: 同優先度タスク間のタイムスライス
- プリエンプション: 高優先度タスクが実行可能になった瞬間(
portYIELD()、portYIELD_FROM_ISR()) - タスクの自発的譲渡:
taskYIELD()の明示的呼び出し
/* スケジューラの制御 */
/* スケジューラの一時停止(タスク切り替えを禁止) */
vTaskSuspendAll();
/* ... コンテキストスイッチが起きては困るクリティカルな処理 ... */
xTaskResumeAll(); /* 再開時にペンディングのスイッチを実行 */
/* 自発的なCPU譲渡 */
taskYIELD(); /* 同優先度の次のタスクへ切り替え */
スケジューラビリティ解析(RM分析)
RM分析でシステムがスケジュール可能かどうかを事前に検証します。
タスク定義:
TaskA: 実行時間C1=2ms, 周期T1=10ms
TaskB: 実行時間C2=3ms, 周期T2=25ms
TaskC: 実行時間C3=2ms, 周期T3=50ms
CPU利用率計算:
U = 2/10 + 3/25 + 2/50 = 0.20 + 0.12 + 0.04 = 0.36 = 36%
RM利用率上限(n=3):
Umax = 3 × (2^(1/3) - 1) ≈ 0.780 = 78%
0.36 < 0.78 → スケジュール可能(全タスクがデッドラインを満たす)
用途・ユースケース
産業制御
- モーション制御: 1kHzのサーボ制御タスクを最高優先度に配置し、スケジューラが確実に1ms周期で実行を保証
- PLCエミュレーション: I/Oスキャンタスク・ラダーロジック実行タスク・HMI通信タスクを優先度で管理
自動車
- AUTOSAR OS: 周期タスク・イベントタスク・バックグラウンドタスクをAUTOSAR仕様のスケジューラで管理
- マルチコアスケジューリング: 現代の自動車MCU(例:AURIX TriCore)は3コアを持ち、コア間のタスク割り当てを事前に決定
IoT
- FreeRTOS on ESP32: Wi-Fi・BLEスタックが専用タスクで動作し、アプリケーションタスクと優先度を分けて共存
- 低消費電力設計: アイドルタスクでCPUをスリープモードへ移行し、次のTick割り込みまで電力を節約
実装・開発のポイント
優先度の逆転防止
優先度逆転は、低優先度タスクが資源を保持したまま高優先度タスクを待たせる現象です。RTOSの優先度継承ミューテックス(PI Mutex)を使うことで防止できます。
/* FreeRTOS: 優先度継承付きミューテックス */
MutexHandle_t sharedMutex = xSemaphoreCreateMutex();
/* 低優先度タスクがこのミューテックスを保持中に高優先度タスクが要求すると、
低優先度タスクの優先度が一時的に引き上げられる(優先度継承) */
応答時間分析(Response Time Analysis)
RM分析より精密な応答時間分析では、各タスクの最悪応答時間Riを反復計算で求めます。
Ri^(0) = Ci
Ri^(k+1) = Ci + Σ[j∈hp(i)] ceil(Ri^(k) / Tj) × Cj
hp(i) = タスクiより高優先度のタスク集合
例:TaskB(C=3ms, T=25ms)について
高優先度TaskA(C=2ms, T=10ms)がある場合:
R^(0) = 3
R^(1) = 3 + ceil(3/10) × 2 = 3 + 1×2 = 5
R^(2) = 3 + ceil(5/10) × 2 = 3 + 1×2 = 5 → 収束
最悪応答時間 = 5ms < デッドライン25ms → OK
スケジューラの無効化に注意
vTaskSuspendAll()やtaskENTER_CRITICAL()でスケジューラ・割り込みを停止する期間は最小限にします。長時間の停止はジッタを増大させ、リアルタイム性を損ないます。
他技術との比較
| 観点 | RTOSスケジューラ | Linuxスケジューラ(CFS) | ベアメタル(スーパーループ) |
|---|---|---|---|
| 決定性 | 高(優先度ベース保証) | 低(公平性重視) | 中(ループ順次実行) |
| 最悪レイテンシ | 数μs〜数十μs | 数ms〜数十ms(PREEMPT_RTで改善) | ループ1周時間に依存 |
| タスク数制限 | メモリ次第(数十〜数百) | 数千〜数万 | 実質的なタスク概念なし |
| オーバーヘッド | 小(数μsのスイッチコスト) | 中 | 最小 |
| 向いている用途 | 組み込みリアルタイム制御 | エッジAI・ファイル処理 | 超シンプル・超低リソース |
スケジューラを正しく活用することは、リアルタイム性・保守性・安全性を両立させた組み込みシステム設計の基本です。タスクの優先度設定とスケジューラビリティ解析を事前に行い、理論的な根拠に基づく設計を心がけることが重要です。