FreeRTOSの排他制御(セマフォ、ミューテックス)


下記の記事から続くFreeRTOSの機能に関する記事です。

https://qiita.com/tom_S/items/ea653880132e1fcfed72

FreeRTOSのセマフォとミューテックスは、他のRTOSと同様排他制御を行うために使用しされます。
あるタスクでセマフォ(orミューテックス)を獲得(ロック)している間は、他のタスクは同じセマフォを獲得(ロック)することができず、獲得しようとした場合はタスク自体がBlocked状態(休止状態)となります。

## FreeRTOSのセマフォ

使用できるセマフォは以下の2種類あります。FreeRTOSのセマフォは優先度逆転が起きる場合の対処をしません。
優先度逆転が起きた際に、資源を獲得したタスクの優先度を上げる処理が欲しい場合はミューテックスを使用します。

|  項目 | 説明 |
|  ------------- | ----------------------------------------------------------------- |
| バイナリセマフォ| 単発の待ち合わせ用のセマフォ。Itron系と同じように使用できる。<br>「vSemaphoreCreateBinary()」で生成 |
| カウンタセマフォ| 複数回の資源獲得・解放を行う場合に、資源獲得回数を記憶しておくことができるセマフォ。<br>「xSemaphoreCreateCounting()」で生成 |

## FreeRTOSのミューテックス

ミューテックスは優先度逆転が起きた場合の優先度引き上げ処理が行われるバイナリセマフォです。
優先度引き上げ処理を具体的に言うと、
資源の獲得中にブロックしたタスクの優先度が、資源を獲得しているタスクの優先度より高い場合、資源を獲得しているタスクの優先度をブロックしたタスクの優先度に設定します。ブロックが解除された際に、優先度は元に戻ります。
また、ミューテックスの資源獲得・解放はセマフォと同じAPI「xSemaphoreTake()」、「xSemaphoreGive()」を使用します。

## API

### vSemaphoreCreateBinary
```c
void vSemaphoreCreateBinary( SemaphoreHandle_t xSemaphore )
```

| 項目1 |  項目2 | 説明 |
| -------- |  ------------------------------ | ------------------------------------------------------ |
|機能|| 単発の待ち合わせ用のセマフォを作成する |
| 引数 | xSemaphore | セマフォID。<br>(SemaphoreHandle_tはポインタとして定義されているので、<br>セマフォIDを格納したいものを引数にする) |
|返り値| | なし |

### xSemaphoreCreateCounting
```c
SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, <br>UBaseType_t uxInitialCount )
```

| 項目1 |  項目2 | 説明 |
| ------------- |  ------------- | ----------------------------------------------------------------- |
|機能|| 資源獲得回数を数えるセマフォを作成する |
| 引数 | uxMaxCount | 獲得回数の最大値 |
| 引数 | uxInitialCount | 獲得回数の初期値。この数値からカウントをスタートする |
|返り値| | セマフォID。<br>(SemaphoreHandle_tはポインタとして定義されているので、<br>セマフォIDを格納したいものを引数にする) |

### xSemaphoreTake
```c
BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore,
                           TickType_t xBlockTime )
```

| 項目1 |  項目2 | 説明 |
| ------------- |  -------------------- | ------------------------------------------------- |
|機能|| セマフォを獲得する |
| 引数 | xSemaphore | 獲得するセマフォID |
|| xBlockTime | タイムアウト時間。最大値を指定する場合はportMAX_DELAYを指定する。永続待ちはできない |
|返り値| | 正常終了したならばpdTRUEを返す |


### xSemaphoreGive
```c
BaseType_t xSemaphoreGive( xSemaphore )
```

| 項目1 |  項目2 | 説明 |
| ------------- |  --------------------------- | ----------------------------------------------------- |
|機能|| セマフォを解放する |
| 引数 | xSemaphore | 解放するセマフォID |
|返り値| | 正常終了したならばpdTRUEを返す |


### vSemaphoreDelete
```c
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore )
```

| 項目1 |  項目2 | 説明 |
| ------------- |  ------------- | ----------------------------------------------------------------- |
|機能|| セマフォを削除する |
| 引数 | xSemaphore | 削除するセマフォID |
|返り値| | なし |


### xSemaphoreCreateRecursiveMutex
```c
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex()
```
| 項目1 |  項目2 | 説明 |
| ------------- |  ------------- | ----------------------------------------------------------------- |
|機能|  | ミューテックスを作成する |
|返り値| | ミューテックスID |


## サンプルソースコード

セマフォを生成し、資源獲得・解放を行うサンプルソースコードを下記に示します。

```c

void semaphoreSampleTask()
{
    SemaphoreHandle_t semHandle;

    vSemaphoreCreateBinary(semHandle);
  //semHandle = xSemaphoreCreateCounting(5, 0); // 最大資源5のカウンタセマフォを生成する場合
  //semHandle = xSemaphoreCreateRecursiveMutex(); // ミューテックスを生成する場合

    for ( ;; )
    {
        xSemaphoreTake(semHandle, portMAX_DELAY);  // タイムアウトを最大値で設定して資源獲得
        
        /* ここに排他した状態で実行したい処理を入れる */
        
        xSemaphoreGive(semHandle); // 資源解放
    }

    vTaskDelete(NULL); /* 何らかのエラーで処理が終了した場合にはタスクを削除 */
}

```