セマフォ制御用API関数の使い方


タスク間の待ち合わせを制御し同期を取るために用意されているのがセマフォです。
セマフォを登録して待つことを「Take」すると呼び、セマフォを解除して待ち合わせを
解除することを「Give」すると呼んでいます。

「BinarySemaphore」は単発の待ち合わせ用のセマフォで、「CountingSemaphore」は、
セマフォで待ち合わせ中に複数回TakeしたりGiveされることがある場合に、回数を記憶
しておくことができるセマフォです。

【セマフォ制御用関数】

セマフォの条件を作成したり、授受を行うためのAPI関数には下記があります。

関数名 機能と書式
vSemaphoreCreateBinary セマフォを生成する
《書式》
   void vSemaphoreCreateBinary(xSemaphoreHandle xSemaphore);
    xSemaphore :セマフォのハンドル値
           宣言部で宣言しておく必要がある。
           正常に生成できなかった場合にはNULLとなる
《使用例》
    xSemaphoreHandle xSemaphore;
    ----
    vSemaphoreCreateBinary(xSemaphore);
    if(xSemaphore != NULL){
      ----
    }
xSemaphoreCreateCounting カウント付きセマフォを生成する
《書式》
  xSemaphoreHandle xSemaphoreCreateCounting(
        unsigned portBASE_TYPE uxMaxCount,
        unsigned portBASE_TYPE uxInitialCount);
    uxMaxCount  :セマフォがカウントする最大カウント数
    uxInitialCount:カウンタの初期値
    戻り値     :正常の場合はセマフォのハンドル値、
             メモリ不足で確保失敗の場合はNULL
《使用例》
  xSemaphoreHandle xSemaphore;
  xSemaphore = xSemaphoreCreateCounting(10, 0);
xSemaphoreTake セマフォをTakeする(待ち合わせをする)
《書式》
   portBASE_TYPE xSemaphoreTake(xSemaphoreHandle xSemaphore,
                portTickType xTicksToWait);
    xSemaphore :セマフォのハンドル値
    xTicksToWait:待ち合わせる最大時間。
           portMAX_DELAYを指定すると永久待ちとなる
    戻り値    :pdPASS:正常の場合  pdFALSE:失敗の場合
xSemaphoreGive セマフォをGiveする(待ち合わせを解除する)
《書式》
   portBASE_TYPE xSemaphoreGive(xSemaphoreHandle xSemaphore);
    xSemaphore:セマフォのハンドル値
    戻り値  :正常ならpdTRUE  失敗なら:pdFALSE
xSemaphoreGiveFromISR 割り込み処理内からセマフォをGiveする(待ち合わせを解除する)
《書式》
   portBASE_TYPE xSemaphoreGiveFromISR(
          xSemaphoreHandle xSemaphore,
          portBASE_TYPE *pxHigherPriorityTaskWoken);
    xSemaphore:セマフォのハンドル値
    pxHigherPriorityTaskWoken:pdTRUEにすると相手タスクを
      レディー状態にする。この場合にはportSWITCH_CONTEXT()
      でコンテキストを戻す必要がある
    戻り値  :正常ならpdTRUE  失敗なら:pdFALSE
xSemaphoreCreateMutex 排他制御用のセマフォを生成する
《書式》
   xSemaphoreHandle xSemaphoreCreateMutex(void);
     戻り値 :生成したセマフォのハンドル値
           失敗した場合にはNULL
     生成したMutexをxSemaphoreTake() と xSemaphoreGive()で使う
xSemaphoreCreateRecursiveMutex 再帰可能な排他制御用のセマフォを生成する
《書式》
  xSemaphoreHandle xSemaphoreCreateRecursiveMutex(void);
   戻り値 :排他セマフォのハンドル値
xSemaphoreTakeRecursive 排他セマフォの待ち合わせをする
《インクルード》 #define configUSE_RECURSIVE_MUTEX 1
《書式》
   xSemaphoreTakeRecursive(xSemaphoreHandle xMutex,
               portTickType xBlockTime);
    xMutex  :排他セマフォのハンドル値
    xBlockTime:セマフォが解除されるのを待つ最大時間
          0にするとすぐ戻る
    戻り値  :pdTRUE:正常 pdFALSE:待ち時間がタイムアウト
xSemaphoreGiveRecursive 排他セマフォの待ち合わせを解除する。同じタスクから繰り返し可能
《書式》
  xSemaphoreGiveRecursive(xSemaphoreHandle xMutex);
     xMutex :排他セマフォのハンドル値
     戻り値 :pdTRUE:正常

【セマフォの使用例】

下記の例題は、3つのタスクがあり、キューを1個、セマフォを1個使う例題です。
まず、タスク3はキューに送られたメッセージを液晶表示器に表示するだけです。

タスク1は無条件に1秒ごとに表示メッセージをキューに送ります。これで
液晶表示器の1行目に1秒間隔で表示されることになります。

タスク2はセマフォをTakeして待ち合わせ、Giveされて待ち合わせが解除
されたらメッセージをキューに送ります。
このセマフォを解除するためにタイマ2を200msecインターバルで動作させ、
その割り込みでセマフォをGiveしています。
これで液晶表示器の2行目には、タイマ2の0.2秒間隔で表示が更新される
ことになります。

結果として、1行目の表示は1秒ごとにカウントアップし、2行目の表示は0.2秒
ごとにカウントアップします。

main関数部のリストが下記となります。
宣言部でセマフォのハンドル用変数(lcdSemaphore)を宣言しておきます。
main関数内部でvSemaphoreCreateBinary関数でセマフォを生成しています。
この生成が成功したら3つのタスクを生成しています。


次に割り込み処理ルーチンと各タスクの内容は下記となります。

割り込み処理では、相手タスクをレディーにする処理は入れず(pdFALSEにして)
セマフォをGiveしています。これでタイマ2の0.2秒間隔でセマフォのGiveが発行
されることになります。Giveが成功、不成功で処理は特に変わらないので結果は
無視しています。

タスク2の中でセマフォをTakeして待ち合わせをしています。したがって
タスク2はほぼ常時セマフォ待ち状態となっていて、タイマ2でGiveされた
瞬間だけレディー状態となりメッセージをキューに送ります。

タスク1は1秒間隔で単純にキューにメッセージを送信するだけです。




★★★ 上記プログラムのプロジェクトファイルダウンロード(sample4)




目次に戻る