1.5.8 マルチスレッドアプリケーションにおけるロックの管理

スレッドセーフな関数は、ロックを使用して同時アクセスから共有リソースを保護します。C ライブラリには、このロックメカニズムを管理し、ヒープなどの共有データの破損を防ぐために再実装できる関数があります。

これらの関数はミューテックス関数です。ミューテックスのライフサイクルは、初期化、反復収集、必要に応じたミューテックスの解放のいずれかです。オプションで、再度必要とされることがない場合にミューテックスが解放されます。ミューテックス関数は、固有のリアルタイムオペレーティングシステム(RTOS)呼び出しをラップします。関数のプロトタイプは以下のとおりです。
_mutex_initialize()
int _mutex_initialize(mutex *m);
この関数は、32 ビットワードのポインタを取得し、有効なミューテックスとして初期化します。
非スレッドアプリケーションの場合、_mutex_initialize() はデフォルトで 0 を返します。したがって、マルチスレッドアプリケーションの場合、_mutex_initialize() は、成功時にゼロ以外の値を返す必要があります。その結果、実行時に、この関数がマルチスレッド環境で使用されていることがライブラリによって認識されます。
_mutex_initialize() が、ミューテックスを初期化してロック解除状態にします。
ミューテックスを使用する場合は、この関数を指定する必要があります。
_mutex_acquire()
void _mutex_acquire(mutex *m);
この関数を呼び出したスレッドは、指定されたミューテックスのロックを取得します。
ミューテックスに所有者がない場合、_mutex_acquire() は即座に復帰します。別のスレッドがミューテックスを所有している場合、_mutex_acquire() は、この関数が利用可能になるまでブロックします。
_mutex_acquire() は、既にミューテックスを所有しているスレッドには呼び出されません。
ミューテックスを使用する場合は、この関数を指定する必要があります。
_mutex_release()
void _mutex_release(mutex *m);
この関数を呼び出したスレッドは、_mutex_acquire() によって取得されたミューテックスのロックを解除します。
ミューテックスは存在し続け、mutex_acquire() へのその後の呼び出しによって再びロックできます。
_mutex_release() は、別の呼び出し元スレッドがミューテックスを所有していると想定します。
ミューテックスを使用する場合は、この関数を指定する必要があります。
_mutex_free()
void _mutex_free(mutex *m);
この関数を呼び出したスレッドは、指定されたミューテックスを解放します。そのミューテックスと関連付けられたオペレーティングシステムリソースはすべて解放されます。ミューテックスは破棄され、再利用できません。
_mutex_free() は、別の呼び出し元スレッドがミューテックスを所有していると想定します。
この関数はオプションです。この関数を指定しなかった場合、C ライブラリによる呼び出しは行われません。
_mutex_*() 関数のパラメータとして使用される mutex データ構造体型は、 ARM® コンパイラツールチェーンヘッダファイルでは定義されませんが、別の場所で定義する必要があります。通常は、RTOS コードの一部として定義されます。
_mutex_*() 関数を呼び出す関数は、ミューテックスデータ構造を保持するために 4 バイトのメモリを作成します。__Heap_Initialize() はそのような関数の 1 つです。
C ライブラリの場合、ミューテックスは、いずれの場所にも配置が可能な 1 つの 32 ビットワードのメモリとして指定されます。ただし、ミューテックスの実装がこれを上回るメモリを必要とした場合、またはミューテックスを特殊なメモリに保存しなければならない場合には、実際のミューテックスを指すポインタとしてデフォルトのミューテックスを処理する必要があります。
_mutex_initialize()_mutex_acquire()、および _mutex_release() の再実装フレームワークの典型的な例を次に示します。ここで、SEMAPHORE_IDCreateLock()AcquireLock()、および ReleaseLock() は RTOS で定義され、(...) は追加パラメータを意味します。
int _mutex_initialize(SEMAPHORE_ID *sid)
{
   /* ミューテックスセマフォの作成 */
    *sid = CreateLock(...);
    return 1;
}
void _mutex_acquire(SEMAPHORE_ID *sid)
{
    /* セマフォを取得するまでタスクはスリープ */
    AcquireLock(*sid, ...);
}
void _mutex_release(SEMAPHORE_ID *sid)
{
    /* セマフォを解放する。*/
    ReleaseLock(*sid);
}
void _mutex_free(SEMAPHORE_ID *sid)
{
    /* セマフォを解放する。*/
    FreeLock(*sid, ...);
}

  • _mutex_release() は、_mutex_acquire() により取得されたミューテックスのロックを解除しますが、ミューテックスはまだ存在し、以降の _mutex_acquire() の呼び出しにより再度ロックできます。
  • ミューテックスが破棄されるのは、オプションのラッパ関数 _mutex_free() が呼び出された場合のみです。ミューテックスが破棄された後では、最初に _mutex_initialize() を呼び出して再度設定しない限り、ミューテックスを使用できません。
関連する概念
1.5.9 再実装したミューテックス関数を確実に呼び出す方法
1.5.11 ARM C ライブラリでのスレッドセーフティ
1.5.12 ARM C++ ライブラリでのスレッドセーフティ
関連する参考文書
1.5.10 マルチスレッド環境での ARM C ライブラリの使用
非機密扱いPDF file icon PDF 版ARM DUI0808CJ
Copyright © 2014, 2015 ARM.All rights reserved.