組み込みソフトウェア開発、特にリアルタイムOS(RTOS)を利用する環境において、「イベントフラグ」は欠かせない同期機構の一つです。

システム内で発生するさまざまな事象(イベント)をビット単位で管理し、タスク間の実行タイミングを制御するために用いられます。

セマフォやミューテックスといった他の同期機構と並び、複雑なリアルタイム制御を実現するための基礎知識といえるでしょう。

本記事では、イベントフラグの基本的な仕組みから、具体的な動作モード、他の同期機構との違いまで詳しく解説します。

イベントフラグの基本概念

イベントフラグとは、特定の事象が発生したことを示す「旗(フラグ)」を複数並べたデータ構造のことです。

一般的には、1つひとつのビットが特定のイベントに対応しており、ビットが「1」であればイベント発生、「0」であれば未発生を意味します。

RTOS(Real-Time Operating System)においては、あるタスクが特定のイベントが発生するまで待ち状態に入り、別のタスクや割り込みハンドラがそのフラグをセットすることで実行を再開させる仕組みとして機能します。

ビットによる多重管理

イベントフラグの最大の特徴は、複数のイベントを1つのオブジェクトで管理できる点にあります。

例えば、8ビットの変数であれば8種類、32ビットの変数であれば32種類の異なるイベントを同時に扱うことが可能です。

これにより、「センサーAのデータが届く」「タイマーがタイムアップする」「ユーザーがボタンを押す」といった独立した事象を、一つのフラグ変数の中で整理して管理できます。

タスクの実行制御

イベントフラグを利用することで、タスクの実行順序を柔軟に制御できます。

特定の条件が整うまでタスクをスリープ(待ち状態)にさせておくことで、CPUのリソースを無駄に消費することなく効率的なプログラム運用が可能になります。

これは、ポーリング(ループによる状態監視)を回避し、低消費電力化や応答性の向上を図る組み込み開発において極めて重要な役割を果たします。

イベントフラグの主な動作モード

イベントフラグの動作には、主に「待ち条件」と「解除後の処理」に関するいくつかのバリエーションが存在します。

これらを適切に選択することで、複雑な同期処理を簡潔に記述できるようになります。

AND待ちとOR待ち

複数のビットを指定してイベントを待つ際、どのような条件で待ちを解除するかを決定するのがAND待ちとOR待ちです。

AND待ちは、指定したすべてのビットが「1」になるまでタスクを停止させるモードです。

例えば、「センサーAの準備完了」と「センサーBの準備完了」の両方が揃った時だけ計算を開始したい場合に利用されます。

一方、OR待ちは、指定したビットのうちどれか一つでも「1」になれば待ちを解除するモードです。

「エラー発生」または「停止ボタン押下」のいずれかが起きた時に例外処理へ遷移させたい場合などに適しています。

自動クリアと手動クリア

イベントフラグがセットされた後、待ちタスクが再開した瞬間にそのフラグを「0」に戻すかどうかを指定できます。

待ち解除と同時にフラグを「0」にする動作を「自動クリア」と呼びます。

自動クリアを使用すると、一回限りのイベント通知を確実に処理でき、次のイベント発生に備える手間を省けます。

これに対し、明示的に関数を呼び出すまでフラグを維持する仕組みを「手動クリア」と呼び、複数のタスクが同じイベントを共有して参照する場合に利用されます。

RTOSにおける他の同期機構との違い

RTOSにはイベントフラグ以外にも、セマフォやミューテックス、メッセージキューといった同期・通信機構が存在します。

それぞれの特性を理解し、用途に合わせて使い分けることが設計の鍵となります。

機能名主な用途特徴
イベントフラグ複数のイベントによる同期ビット単位でのAND/OR条件指定が可能
セマフォリソース管理・排他制御数値(カウンタ)による資源の個数管理
ミューテックス厳格な排他制御所有権の概念があり、優先順位逆転を防止
メッセージキュータスク間データ通信値そのものを送信し、順序を保証して受け渡す

セマフォとの使い分け

セマフォは主に「残りいくつ利用可能か」というリソースの数を管理するのに適していますが、特定の事象の組み合わせを表現することはできません。

例えば、「リソースAが空いている、かつスイッチが押された」という条件をセマフォだけで作ろうとすると非常に複雑になります。

このような論理的な条件の組み合わせをシンプルに表現できるのがイベントフラグの強みです。

イベントフラグの活用シーン

実際の組み込み開発現場において、イベントフラグがどのように活用されているか具体例を見てみましょう。

1. 複数センサーのデータ同期

自動運転制御やロボット制御では、ジャイロセンサー、加速センサー、距離センサーなど、複数のソースからデータを取得する必要があります。

それぞれのセンサーが独立した周期でデータを更新する場合、メインの計算タスクはすべてのセンサーデータが更新されるまで待機しなければなりません。

ここでイベントフラグのAND待ちを使用すれば、全センサーの準備が整った瞬間にのみ計算処理を実行させることができます。

2. 割り込みハンドラからの通知

割り込みハンドラ(ISR)内では、時間のかかる処理を行うことは推奨されません。

そのため、割り込みが発生したという事実だけをイベントフラグで記録し、実際の処理は優先度の高い通常タスクに任せるという手法が一般的です。

イベントフラグはオーバーヘッドが少ないため、高速なレスポンスが求められる割り込み処理との相性が抜群です。

3. 異常監視とシステム停止

システム内の各所で発生するエラービットを1つのイベントフラグに集約することができます。

監視タスクがOR待ちで待機しておくことで、どこか1箇所でも異常フラグが立てば即座に緊急停止やエラーログ出力へ移行できます。

実装のイメージ(サンプルコード)

ここでは、一般的なRTOS(μITOSやT-Kernelなど)を意識したC言語風の擬似コードで、イベントフラグの操作イメージを示します。

C言語
/* イベントフラグのID定義 */
#define EVENT_ID_SENSOR_A  (1 << 0)  /* 0番目のビット */
#define EVENT_ID_SENSOR_B  (1 << 1)  /* 1番目のビット */

/* タスクA:センサーデータの受信を待って処理を行う */
void Task_Main(void) {
    uint32_t pattern;

    while (1) {
        /* センサーAとBの両方がセットされるまでAND待ち(自動クリアあり) */
        wait_event_flag(ID_FLG1, (EVENT_ID_SENSOR_A | EVENT_ID_SENSOR_B), 
                        TWF_ANDW | TWF_CLR, &pattern);

        /* ここに来た時は両方のイベントが発生している */
        process_data();
    }
}

/* 割り込みハンドラ:センサーAの検知 */
void ISR_SensorA(void) {
    /* センサーAのフラグをセットする */
    set_event_flag(ID_FLG1, EVENT_ID_SENSOR_A);
}

このコードでは、wait_event_flagによってタスクが効率的に休止し、CPUを他の処理に譲っている点がポイントです。

実装時の注意点とベストプラクティス

イベントフラグは強力ですが、設計を誤るとデバッグが困難な不具合を招くこともあります。

フラグの競合とリセットタイミング

手動クリア(TWF_CLRを指定しない場合など)を使用する際は、どのタイミングでフラグを落とすかを慎重に決める必要があります。

フラグをクリアし忘れると、次回の待ち処理が即座に解除されてしまい、意図しない無限ループが発生する恐れがあります。

特別な理由がない限り、基本的には自動クリアモードを使用するのが安全です。

デッドロックの回避

タスクAがタスクBの出すフラグを待ち、同時にタスクBがタスクAの出すフラグを待つという状況が発生すると、システムは永久に停止します。

これをデッドロックと呼びます。

イベントフラグを使用する際は、フラグを「待つ側」と「送る側」の関係を設計書などで明確に整理しておくことが重要です。

優先順位逆転への配慮

イベントフラグそのものには、ミューテックスのような優先順位継承機能はありません。

低い優先度のタスクがフラグをセットするのを高い優先度のタスクが待っている間、中間の優先度を持つ無関係なタスクがCPUを占有してしまうと、システムのリアルタイム性が損なわれます。

クリティカルな制御を行う場合は、タスクの優先度設計を綿密に行う必要があります。

まとめ

イベントフラグは、組み込みシステムにおけるタスク間同期の要(かなめ)となる機能です。

1ビットごとのフラグ管理により、AND/ORといった柔軟な条件待ちを軽量なオーバーヘッドで実現できる点が大きなメリットです。

セマフォやメッセージキューとの違いを正しく理解し、自動クリアの設定やデッドロック対策に注意を払うことで、堅牢なリアルタイム制御システムを構築できます。

組み込み開発のスキルアップを目指すなら、まずはこのイベントフラグの挙動を完璧にマスターし、効率的なマルチタスク設計を実践してみてください。