ワンタイム初期化

一部の C ライブラリーは、動的な初期化用に設計されています。この初期化では、ライブラリー内の最初のプロシージャーが呼び出されたときに、ライブラリーのグローバル初期化が行われます。

単一スレッドのプログラムでは、 これは普通は次のコード・フラグメントのように、 各ルーチンへの入り口で変数が調べられる、 静的変数を使用してインプリメントされます。

static int isInitialized = 0;
extern void Initialize();

int function()
{
        if (isInitialized == 0) {
                Initialize();
                isInitialized = 1;
        }
        ...
}

マルチスレッド・プログラムにおいて動的にライブラリーを初期化するには、1 つの初期化フラグだけでは不十分です。このフラグを、 ライブラリー関数を同時に呼び出している複数のスレッドによって変更されないように保護する必要があります。 フラグを保護するには mutex を使用しなければなりませんが、mutex は使用の前に初期化する必要があります。 mutex が 1 回だけ初期化されるようにするには、 この問題に対する再帰的解決策が必要です。

マルチスレッド・プログラムで同じ構造体を保持するには、pthread_once サブルーチンを使用してください。それ以外の場合、ライブラリーを使用する前に、 ライブラリーがエクスポートした初期化関数を明示的に呼び出すことによって、 ライブラリー初期化を達成する必要があります。 pthread_once サブルーチンは、mutex と条件変数の初期化の別の方法も提供します。

ワンタイム初期化について、次のセクション以降でさらに詳しく説明します。

ワンタイム初期化オブジェクト

初期化の固有性は、ワンタイム初期化オブジェクト によって確保することができます。 これは、pthread_once_t データ型を持つ変数です。 AIX® および他の大部分のスレッド・ライブラリーのインプリメンテーションでは、 pthread_once_t データ型は構造体です。

ワンタイム初期化オブジェクトは、一般にグローバル変数です。 これは、次の例に示すように、PTHREAD_ONCE_INIT マクロで初期化する必要があります。

static pthread_once_t once_block = PTHREAD_ONCE_INIT;

初期化は、初期スレッドまたは他の任意のスレッド内でも実行できます。 いくつかのワンタイム初期化オブジェクトを、同じプログラムで使用することができます。 唯一の要件は、ワンタイム初期化オブジェクトをマクロで初期化するということです。

ワンタイム初期化ルーチン

pthread_once サブルーチンは、最初に呼び出されたときは、 指定されたワンタイム初期化オブジェクトと関連する指定された初期化ルーチンを呼び出し、 それ以外の場合は、何も行いません。 同じワンタイム初期化オブジェクトには、 常に同じ初期化ルーチンを使用する必要があります。 初期化ルーチンには、以下のプロトタイプがなければなりません。
void init_routine();

pthread_once サブルーチンには、取り消しポイントがありません。 ただし、初期化ルーチンは取り消しポイントを提供することができます。 そして取り消し機能が使用可能になっている場合、 pthread_once サブルーチンを呼び出す最初のスレッドを、 初期化ルーチンの実行中は取り消すことができます。 この場合、そのルーチンは実行中とは見なされず、 次に pthread_once サブルーチンを呼び出すと、 初期化ルーチンが再び呼び出される結果となります。

ワンタイム初期化ルーチンでは、特にファイルのオープン、mutex のロック、 あるいはメモリーの割り当てなどの非等べき操作の実行時には、 クリーンアップ・ハンドラーを使用することをお勧めします。

ワンタイム初期化ルーチンを、mutex または条件変数の初期化、 あるいは動的初期化の実行に使用することができます。 マルチスレッド・ライブラリーでは、上記に示されているコード・フラグメント (void init_routine();) は次のように書かれます。

static pthread_once_t once_block = PTHREAD_ONCE_INIT;
extern void Initialize();

int function()
{
        pthread_once(&once_block, Initialize);
        ...
}