1

セマフォで保護された、スレッド間で共有する必要のある配列があります。次のように、初期化コードを複数回呼び出すことができる関数「コンストラクター」内に配置しました。

#include <stdbool.h> //for bool
#include <semaphore.h>

sem_t global_mutex;
char global_array[N]; // Protected with global_mutex

struct my_struct *new_my_struct(){
    static bool is_init = false; // This will be initialized only once, right?
    if (!is_init){                         // 1
        sem_init(&global_mutex, 0, 1);     // 2
        sem_wait(&global_mutex);           // 3
        if (!is_init){                     // 4
           is_init = true;                 // 5
           ... initialize global_array ... // 6
        }
        sem_post(&global_mutex);           // 7
    }

    ... proceed on the create and return a my_struct pointer ...
}

理想的な世界では、スレッドは1から7まで実行され、配列を初期化してクリティカル領域を終了します。別のスレッドが2で停止した場合でも、4のテストはfalseになり、配列は上書きされません。スレッドが1でスタックし、セマフォを再初期化した場合にどうなるかについてはあまり考えていませんが、最初に実行するスレッドによってtrueに設定されている限り、それほど問題にはならないと思います。is_init

ここで、スレッドが4で停止し、別のスレッドが開始から完了まで実行され、初期化と入力が行われる場合、競合状態が発生しますglobal_array。スレッドが4回の実行で停止すると、配列が再初期化され、最初のスレッドによって保存された状態が削除されます。

その競合状態に悩まされない方法があるかどうか(おそらくstatic?の巧妙な使用)、または並行性がないときに初期化コードをコンストラクターから分離してメインスレッドで使用する必要があるかどうかを知りたいです。

このコードは使用中であり、まだ競合状態に悩まされていません。しかし、その可能性はわかっているので、修正したいと思います。

4

2 に答える 2

2

セマフォの実際の使用が実際にミューテックスとして使用されている場合は、それだけを使用してpthread_mutex_tください。これらは静的に初期化できるため、問題は解消されます。

構文は次のようになります

pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;

グローバルオブジェクトの動的初期化が本当に必要な場合は、を調べてくださいpthread_oncepthread_once_tこれは、そのようなタスクのためにPOSIXによって予測されるタイプ( )および関数です。

于 2012-09-17T11:57:43.330 に答える
1

スレッドセーフなレイジー初期化を行う方法はいくつかありますが、これはその1つではありません。

pthread_onceは1つの方法であり、実際にはミューテックス(静的に初期化される)であるグローバルミューテックスを使用して初期化を同期することは別の方法です。実装はstaticローカル変数のスレッドセーフな初期化を保証するかもしれませんが、そうする必要はありません(少なくとも、C11より前ではなく、私はそれをチェックしていません)。

ただし、実際の初期化を同期する場合でも、ダブルチェックロックがCまたはPosixで機能することは保証されません両方のスレッドで何らかの同期を行わずに、別のスレッドで設定された1つのスレッドのフラグをチェックするのはデータの競合です。の実装はpthread_once、初期化がすでに行われている一般的なケースで高速になるように最善を尽くす必要があります。実装で関数スコープの静的変数のスレッドセーフな初期化が保証されている場合は、それも最善を尽くします。自分が何をしているのかを本当に理解していない限り(たとえばpthread_once、新しいシステムのために自分自身を実装している場合)、一般的なケースでコストのかかるロックを回避するために、自分の試みを実行するよりも、それらの1つを使用してください。

于 2012-09-17T12:06:50.307 に答える