Nucleus SEのセマフォ:概要、設定、API要点
RTOS Revealedシリーズを表示
セマフォは組み込みシステムにおける共有リソースへのアクセス同期のための基礎的メカニズムです。タスクが競合なくリソースの制御を安全に取得・解放できるようにします。
セマフォの使用
Nucleus SEでは、セマフォサポートはビルドプロセスで有効化されます。単一アプリケーションで最大16個のセマフォを設定可能。セマフォを使用しない場合、関連データ構造とAPIコードは最終バイナリから除外され、フットプリントを削減できます。
セマフォは単純に、複数タスクが安全に操作できるよう保護された8ビットカウンタです。タスクはObtainを呼んでカウンタをデクリメントし、Releaseでインクリメントします。カウンタがゼロのセマフォを取得しようとした場合、APIオプションとシステム設定に応じて、エラーを返すか、セマフォが利用可能になるまでタスクをサスペンドします。
セマフォの設定
セマフォ数
セマフォはnuse_config.h内の#define文で定義されます。鍵となるマクロはNUSE_SEMAPHORE_NUMBERで、アプリケーションが使用するセマフォスロット数を指定します。デフォルト値は0で、セマフォサポートなしを意味します。有効値は0~16。無効値はnuse_config_check.h(nuse_config.c経由でインクルード)によりコンパイル時#errorをトリガーします。
NUSE_SEMAPHORE_NUMBERを非ゼロに設定すると、セマフォサブシステムが活性化:データ構造が適切にサイズ設定され、API有効化シンボルが処理されます。
API有効化
各Nucleus SE API呼び出しは、nuse_config.hの専用有効化マクロでガードされます。セマフォ関連のシンボルは:
NUSE_SEMAPHORE_OBTAINNUSE_SEMAPHORE_RELEASENUSE_SEMAPHORE_RESETNUSE_SEMAPHORE_INFORMATIONNUSE_SEMAPHORE_COUNT
デフォルトではすべてFALSEで、対応するサービスコールを無効化し、実装をビルドから除外します。特定のAPIを有効にするには、そのマクロをTRUEに設定します。
デフォルトnuse_config.hからの抜粋:
#define NUSE_SEMAPHORE_NUMBER 0 /* システム内のセマフォ数 – 0-16 */ #define NUSE_SEMAPHORE_OBTAIN FALSE /* サービスコール有効化 */ #define NUSE_SEMAPHORE_RELEASE FALSE /* サービスコール有効化 */ #define NUSE_SEMAPHORE_RESET FALSE /* サービスコール有効化 */ #define NUSE_SEMAPHORE_INFORMATION FALSE /* サービスコール有効化 */ #define NUSE_SEMAPHORE_COUNT FALSE /* サービスコール有効化 */
セマフォを設定せずにAPIを有効化すると(NUSE_Semaphore_Count()は常に利用可能)、コンパイルエラーになります。有効化されていないAPIを呼び出すと、実装が省略されているためリンクエラーが発生します。
セマフォサービスコール
Nucleus SEには8つのセマフォ関連サービスコールがあります。最初の5つが完全実装され、残り3つは将来の拡張用プレースホルダーです。
- Obtain –
NUSE_Semaphore_Obtain() - Release –
NUSE_Semaphore_Release() - Reset –
NUSE_Semaphore_Reset() - Information –
NUSE_Semaphore_Information() - Count –
NUSE_Semaphore_Count() - Create – Nucleus SEでは未実装
- Delete – Nucleus SEでは未実装
- List All – Nucleus SEでは未実装
ObtainとRelease操作
セマフォの核心操作は、Obtain(デクリメント)とRelease(インクリメント)です。Nucleus RTOSはオプションのサスペンドとタイムアウト付きの柔軟なObtain APIを提供します。Nucleus SEはこの振る舞いを模倣しますが、タスクサスペンドはオプションでタイムアウトは非サポート。
Nucleus RTOS Obtain API
プロトタイプ:
STATUS NU_Obtain_Semaphore(NU_SEMAPHORE *semaphore, UNSIGNED suspend);
パラメータ:
semaphore– セマフォ制御ブロックへのポインタ。
suspend–NU_NO_SUSPEND、NU_SUSPEND、またはタイムアウト値。
戻り値:
NU_SUCCESS– 操作成功。
NU_UNAVAILABLE– セマフォ値がゼロ。
NU_INVALID_SEMAPHORE– 無効なセマフォポインタ。
NU_INVALID_SUSPEND– 非タスクコンテキストからのサスペンド試行。
NU_SEMAPHORE_WAS_RESET– タスクサスペンド中にセマフォリセット。
Nucleus SE Obtain API
プロトタイプ:
STATUS NUSE_Semaphore_Obtain(NUSE_SEMAPHORE semaphore, U8 suspend);
パラメータ:
semaphore– セマフォインデックス。
suspend–NUSE_NO_SUSPENDまたはNUSE_SUSPEND。
戻り値:
NUSE_SUCCESS– 操作成功。
NUSE_UNAVAILABLE– セマフォ値がゼロ。
NUSE_INVALID_SEMAPHORE– 無効なセマフォインデックス。
NUSE_INVALID_SUSPEND– 非タスクからのサスペンド試行、またはブロッキングAPI無効。
NUSE_SEMAPHORE_WAS_RESET– サスペンド中にセマフォリセット。
実装のハイライト
ブロッキング無効時、実装はカウンタが非ゼロかチェックし、デクリメントしてNUSE_SUCCESSを返します。ゼロならNUSE_UNAVAILABLEを返します。
if (NUSE_Semaphore_Counter[semaphore] != 0) { NUSE_Semaphore_Counter[semaphore]--; return_value = NUSE_SUCCESS; } else { return_value = NUSE_UNAVAILABLE; } ブロッキング有効時、ルーチンはdo…whileループに入り、セマフォ取得を試みます。カウンタがゼロでsuspendがNUSE_SUSPENDならタスクをブロック。解放時に最初の待機タスクがウェイクアップし、ループが取得をリトライします。 do { if (NUSE_Semaphore_Counter[semaphore] != 0) { NUSE_Semaphore_Counter[semaphore]--; return_value = NUSE_SUCCESS; suspend = NUSE_NO_SUSPEND; } else { if (suspend == NUSE_NO_SUSPEND) { return_value = NUSE_UNAVAILABLE; } else { NUSE_Semaphore_Blocking_Count[semaphore]++; NUSE_Suspend_Task(NUSE_Task_Active, semaphore << 4 | NUSE_SEMAPHORE_SUSPEND); return_value = NUSE_Task_Blocking_Return[NUSE_Task_Active]; if (return_value != NUSE_SUCCESS) { suspend = NUSE_NO_SUSPEND; } } } } while (suspend == NUSE_SUSPEND);
Nucleus RTOS Release API
プロトタイプ:
STATUS NU_Release_Semaphore(NU_SEMAPHORE *semaphore);
パラメータ:
semaphore– セマフォ制御ブロックへのポインタ。
戻り値:
NU_SUCCESS– 操作成功。
NU_INVALID_SEMAPHORE– 無効なセマフォポインタ。
Nucleus SE Release API
プロトタイプ:
STATUS NUSE_Semaphore_Release(NUSE_SEMAPHORE semaphore);
パラメータ:
semaphore– セマフォインデックス。
戻り値:
NUSE_SUCCESS– 操作成功。
NUSE_INVALID_SEMAPHORE– 無効なセマフォインデックス。
NUSE_UNAVAILABLE– カウンタが既に255;インクリメント不可。
実装のハイライト
リリースルーチンはまずカウンタが最大値(255)未満かチェック。そうならインクリメント。ブロッキング有効でこのセマフォで待機タスクがいれば、最初の1つをウェイクアップ。
NUSE_CS_Enter(); if (NUSE_Semaphore_Counter[semaphore] < 255) { NUSE_Semaphore_Counter[semaphore]++; return_value = NUSE_SUCCESS; #if NUSE_BLOCKING_ENABLE if (NUSE_Semaphore_Blocking_Count[semaphore] != 0) { NUSE_Semaphore_Blocking_Count[semaphore]--; for (U8 index = 0; index < NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_SEMAPHORE_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == semaphore)) { NUSE_Task_Blocking_Return[index] = NUSE_SUCCESS; NUSE_Wake_Task(index); break; } } } #endif } else { return_value = NUSE_UNAVAILABLE; } NUSE_CS_Exit(); return return_value;
タスクがセマフォでサスペンドされている場合、リリースすると最初の待機タスクがウェイクアップし、実行を継続できます。
次の記事ではイベントフラググループとその関連データ構造を探ります。
Colin Wallsは電子業界で30年以上の経験を持ち、主に組み込みソフトウェアに注力。会議で頻繁に講演し、技術記事を執筆し、組み込みソフトウェアに関する2冊の著書がある。Mentor Embedded(Mentor Graphics組み込みソフトウェア部門)の組み込みソフトウェアテクノロジストで、英国在住。ブログはhttps://blogs.mentor.com/colinwalls。メールはcolin_walls@mentor.com。
埋め込み
- UCAS、インフォシスとの契約を3年延長し自動化を推進
- カムロック完全解説:キャビネットを目立たず確実に施錠する仕組み
- アイボルト(アイスクリュー)とは:設計と用途のプロフェッショナルガイド
- ステンレス鋼解説:組成・製造プロセス・グローバルインパクト
- 自動車サービスライター(フロント受付)の役割、業務、キャリアパス
- Nucleus SEのメールボックス:設定と使用の実践ガイド
- Nucleus RTOSのセマフォ:ユーティリティサービスとデータ構造
- イベントフラググループの習得:Nucleus RTOS/SEのユーティリティサービスとデータ構造
- Nucleus SEのイベントフラググループ:設定とAPI使用の入門ガイド
- Nucleus SEのキュー:導入とコアサービスコール
- C# 入出力の基礎:ユーザー入力と出力の基本をマスター