0

私が抱えている問題は次のとおりです。「親」が0から4までのforループを通過します。各反復で、12個の数値(0から4)の「セグメント」を出力する3つのスレッドがあります。 11)。

たとえば、親ループが0の場合、スレッド0は0を出力し、スレッド1は4を出力し、スレッド2は8を出力します。

親ループが1の場合、スレッド0は1を出力し、スレッド1は5を出力し、スレッド2は9を出力します。

したがって、理想的には、出力は0 1 2 3 4 5 6 7 8 91011になります。スレッドがいつ実行されるかを判断できないことはわかっているので、正確にその順序になるわけではありませんが、スレッドが3 4または5を印刷する前に、少なくとも01と2を印刷したいと思います。

それが私が問題を抱えていることです。あるスレッドまたは別のスレッドがほこりの中に残って、そのセグメントを印刷しないか、他のスレッドと一緒にそのセグメントを完全に印刷しないようです。これは、セマフォを完全に理解するために私が行っている問題です。

2つのセマフォがあります。1つはスレッドが機能しているときに親(プロデューサー?)をブロックし、もう1つはプロデューサーが次のインデックスにインクリメントするまで各スレッドをブロックします。このようにして、お互いが終了するのを待ってから続行するように強制できると思いましたが、何らかの理由で問題が発生しています。

これが私のコードです:

#include <semaphore.h>
#include <stdio.h>
#include <pthread.h>

#define maxNum 12

sem_t parentSem;
sem_t threadSem;
int finishedThreads;
int done = 0;
int stuff[12];
int i;

void* threadFunction(int m){
    int printNum;
    int baseNum;
    //Determine the value the thread should start at
    baseNum = (double)(maxNum/3) * m;
    while(!done){ //ensure thread doesn't exit before parent is done with whole loop
        //wait for parent to increment
        sem_wait(&threadSem);
        printNum = baseNum + i;

            //keep track of how many threads are finished to let parent continue
        finishedThreads++;
        if(finishedThreads == 3){
                    //let parent continue if all threads are finished
            sem_post(&parentSem);
        }
    }

}

int main(int argc, char** argv[]){

    sem_init(&parentSem, 0, 1);
    sem_init(&threadSem, 0, 0);
    int rc;
    pthread_t threads[3];
    int l; 
    for(l = 0; l < 12; l++){
        stuff[l] = l;
    }
    int j;
    for(j = 0; j < 3; j++){
        rc = pthread_create(&threads[i], NULL, threadFunction, (void*) j);

    }
    int k;
    for(i = 0; i < 4; i++){
        sem_wait(&parentSem); //wait for children here (initially sem set to 1)
        finishedThreads = 0; //set finished thread counter to 0
        for(k = 0; k < 3; k++){
            //increment thread semaphore to 3 so each thread can run
            sem_post(&threadSem);
        }
    }
    for(i = 1; i < 3; i++){
        pthread_join(threads[i], NULL);
    }



}

親がインクリメントする前にすべてのスレッドが実行されるようにするにはどうすればよいですか?すべてのスレッドが「ラウンド」ごとに実行され、遅れることがないようにするにはどうすればよいですか?各スレッドが1回実行されるのではなく、同じスレッドが2回実行されることがあります。

どうもありがとうございました。

編集:新しいコードの状態:(スレッド関数)

while(!done){

    printf("Thread %d not done yet...\n", m);
    if(m == 0){
        sem_wait(&threadSem0);
    }else if(m == 1){
        sem_wait(&threadSem1);
    }else if(m == 2){
        sem_wait(&threadSem2);
    }
    printNum = baseNum + i;
    printf("Thread %d past waiting, number segment: %d\n", m, printNum);

    finishedThreads++;
    if(finishedThreads == 3){
        sem_post(&parentSem);
    }
}

親部分:

for(i = 0; i < 4; i++){
    printf("In parent for loop, counter: %d\n", i);
    printf("Parent past wait semaphore\n");
    finishedThreads = 0;
    if(i == 3) done = 1;
    sem_post(&threadSem0);
    sem_post(&threadSem1);
    sem_post(&threadSem2);
    sem_wait(&parentSem);
}
for(i = 1; i < 3; i++){
    pthread_join(threads[i], NULL);
}
4

2 に答える 2

0

You're in need of a barrier, specifically a reusable one. It might be useful to take a look at Allen Downey's Little Book of Semaphores, section 3.6.7, reproduced here (PDF). The code is in Python, but the gist of it is clear enough. It requires one mutex and two counting semaphores, and in your case you've 4 participants in the barrier.

You could control which thread gets woken up first by setting thread priorities so that the first thread is the most important, and so on.

于 2013-03-11T05:40:05.183 に答える
0

finishedThreads各スレッドがキャッシュされたコピーのみを使用しないようにするには、atomic にアクセスする必要があります。あなたのプログラムは、最適化 (*) なしでコンパイルされたときに動作しますか?

C++ でこれを行う適切な方法は、 を使用することstd::atomicです。この質問の完全な回答を参照してください。

アップデート:

あなたの場合のように、スレッドがすばやくループしている場合、すべての子スレッドに 1 つのセマフォを使用すると問題が発生する可能性があります。この問題を解決するには、子スレッドごとに 1 つのセマフォを使用する必要があります。

sem_t threadSem[3];

// ...

sem_wait(&threadSem+m);

// ...

for (i = 0; i < 3; i++)
    sem_init(threadSem+i, 0, 0);

// ...

    for(k = 0; k < 3; k++){
        //increment each thread semaphore so each thread can run
        sem_post(threadSem+k);
    }

私が早い段階で見つけられなかった別のいくつかのこと:

iでインクリメントを行うには、変数を使用しますthreadFunction。これは機能しません。正しい式は のみに依存する必要がありますm。各スレッドには独自のbaseNumとのコピーがあるprintNumため、問題なく使用できます。

baseNum = (double)(maxNum/3) * m;
while(!done){ //ensure thread doesn't exit before parent is done with whole loop
    //wait for parent to increment
    sem_wait(&threadSem);
    printNum++;
    // ....

コードには、子スレッドの数に依存するものがたくさんあります。そのために定数を使用することをお勧めします( のようにmaxNum)。

done子スレッドの作業の終了を示す変数を設定しません。

volatile int done;

// in threadFunction

 // wait for start
sem_wait(threadSem+m)
while(!done){ 
    // thread work here
    // ...
    //wait for parent to increment at the end of the loop
    sem_wait(threadSem+m);
}

// in main

for(k = 0; k < 3; k++){
    //increment each thread semaphore so each thread can run
    if (i == 4) done = 1;
    sem_post(threadSem+k);
}

もちろん、「またはミューテックス」ルールdoneにも従う必要があります。volatile

最後にすべてのスレッドに参加するわけではありません。

for(i = 0; i < 3; i++){
    pthread_join(threads[i], NULL);
}

(*) gcc を使用している場合は、パラメーターを使用し-O0-g.

于 2013-03-10T22:04:20.543 に答える