3

pthreads で書かれたマルチスレッドの C プログラムがあります。自分のしていることが正しいかどうか知りたい。現在、プログラムは最適化がない場合に実行されるようです。しかし、最適化を使用すると失敗します。私はその理由を理解しようとしています。

私が使用している基本的なマルチスレッド同期が正しいかどうかを知りたいです。関連する部分のみを含む短いバージョンを次に示します。これがマルチスレッドの正しい方法かどうか教えてください。

仕組み: 各労働者には、やるべき仕事がたくさんあります。ワーカー スレッドが最初に開始されます。次に、メイン スレッドによってジョブが割り当てられるまで待機します。彼らは仕事を完了し、メインスレッドを親密にし、再び待機に戻ります.

メイン スレッドは N 個のワーカーにジョブを割り当て、開始するように信号を送ります。次に、それらの完了を待って、通常の作業を再開します。

各ワーカー スレッドには、workerCtx という名前のコンテキスト変数があります。これにより、ワーカーが必要とするすべての関連情報と、mutex および cond 変数が保存されます。

メインスレッドにもミューテックスと cond 変数があります。

また、親には、threadCompletionCount という変数があります。作業を割り当てる前の初期状態では、この変数は 0 です。各ワーカー スレッドが完了すると、ミューテックスの保護下でこの変数を 1 つ増やし、親スレッドに通知します。親スレッドは、この変数がワーカーの数と等しくなると、すべてのワーカーが完了したことを認識します。

これは workerCtx の短いバージョンです

typedef enum {INITIALIZE = 0 , WAIT = 1, WORK1 = 2, WORK2 =3, DIE = 4} worktype_t;

typedef struct workerCtx_t
{
    int id;

    pthread_mutex_t mutex;
    pthread_cond_t cond;

    pthread_mutex_t * parentMutex;
    pthread_cond_t * parentCond;
    int * parentThreadCompletionCount;

    worktype_t workType;

    //Other application specific variables follow.
}workerCtx_t;

ここで、mutex と cond は、このスレッドに固有のローカルの mutex と cond 変数を参照します。parentMutex と parentCond は、親の変数を参照する変数です。すべてのスレッドが同じparentMutexとparentCondを指しています。

メインスレッドの仕組みは次のとおりです。

void waitForWorkerCompletion()
{
    int status;

    status = pthread_mutex_lock(&mutex);
    while (threadCompletionCount < NUM_WORKERS) 
    {
        status = pthread_cond_wait(&cond, &mutex);
    }
    status = pthread_mutex_unlock(&mutex);

    status = pthread_mutex_lock(&mutex);
        threadCompletionCount = 0;
    status = pthread_mutex_unlock(&mutex);
}

void assignWorkToWorker(worktype_t workType)
{
    for(int i=0; i<NUM_WORKERS; i++)
    {
        pthread_mutex_lock(&(workerCtxs[i]->mutex) );
            workerCtxs[i]->workType = workType;
            pthread_cond_signal(&(workerCtxs[i]->cond) );
        pthread_mutex_unlock(&(workerCtxs[i]->mutex));      
    }
    waitForWorkerCompletion();
}

void setup
{
    for(int i=0; i<NUM_WORKERS; i++)
    {       
        workerCtxs[i]->id = i;
        workerCtxs[i]->workType = WAIT;

        assert( pthread_mutex_init(&(workerCtxs[i]->mutex), NULL) == 0) ;
        assert( pthread_cond_init(&(workerCtxs[i]->cond), NULL) == 0);

        workerCtxs[i]->parentMutex = &mutex;
        workerCtxs[i]->parentCond = &cond;
        workerCtxs[i]->parentThreadCompletionCount = &threadCompletionCount;

        pthread_create (&(workers[i]), NULL, workerMain, (workerCtxs[i]) );

    }
}

int main()
{
    setup()

    For each work (workType_t workType) that comes up
        assignWorkToWorker(workType);
}

各ワーカーが行うことは次のとおりです。

void signalCompletion(workerCtx_t * ctx)
{
    pthread_mutex_lock(&ctx->mutex);
        ctx->workType = WAIT;
    pthread_mutex_unlock(&ctx->mutex);

    int rc = pthread_mutex_lock(ctx->parentMutex);
        *(ctx->parentThreadCompletionCount) = *(ctx->parentThreadCompletionCount) + 1;
        pthread_cond_signal(ctx->parentCond);
    rc = pthread_mutex_unlock(ctx->parentMutex);
}

void * workerMain(void * arg)
{
    workerCtx_t * ctx = (workerCtx_t *) arg;

    while(1)
    {
        pthread_mutex_lock(&ctx->mutex);
        while(ctx->workType == WAIT);
        {
            int status = pthread_cond_wait(&ctx->cond, &ctx->mutex);
        }
        pthread_mutex_unlock(&ctx->mutex);

        if(ctx->workType == INITIALIZE)
        {
            init(ctx);
            signalCompletion(ctx);
        }
        else if(ctx->workType == WORK1)
        {
            doWork1(ctx);
            signalCompletion(ctx);
        }
        else if(ctx->workType == WORK2)
        {
            doWork2(ctx);
            signalCompletion(ctx);
        }
        else if(ctx->workType == DIE)
        {
            signalCompletion(ctx);
            break;
        }
    }

    return NULL;
}

これを十分に理解しやすくし、投稿されたコードからすべてのアプリケーション指向の詳細を取り除いたことを願っています。このコードは、マルチスレッド部分を処理するだけです。これでプログラムがハングします。gdb を使用すると、waitForWorkerCompletion()メソッドで待機中であることがわかります。

このマルチスレッド モデルは正しいですか??

4

2 に答える 2

4

なんてこった、これを答えにします。

次の行は非常に疑わしいようです。

while(ctx->workType == WAIT);

そこにセミコロンが必要だとは思いません。これにより、さまざまな奇妙な競合状態が発生する可能性があります...これは、最適化されていないビルドと最適化されたビルドで動作が異なる理由を説明できます。

それ以外の場合、このコードに問題はありません。ワーカー プールを使用するのは少し奇妙な方法ですが、うまくいくように思えます。

于 2012-08-30T00:09:58.557 に答える
0

次のグローバル宣言がどこかにあると仮定すると、何も問題はありません。

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int threadCompletionCount = 0;
workerCtx_t workerCtxs[NUM_WORKERS];
于 2012-08-29T23:44:28.327 に答える