0

ライブラリを使用して、C でスレッドを使用してプログラミングする方法を学習しようとしていpthreadsます。私のスレッド関数には、ネストされた for ループがあります。

void* thread_func(void* a) {
    int i, t;
    struct type *b = (struct type*)a;
    int start = b->start;
    int stop = b->stop;
    for(t = 0; t < 1000; t++) {

        for(i = start; i < stop; i++) {
        /* This inner loop is evenly divided among the threads.*/
        /***** Calculation*****/
        }
    }
    return NULL;
}

内側の for ループでの計算は、外側の for ループの前の t ステップの結果に依存するため、スレッドは続行する前に、他のスレッドが現在の t ステップを終了するまで待機する必要があります。次の t ステップを続行する前に、すべてのスレッドが各 t ステップを終了するのを待つ方法はありますか? 使用しようとしましpthread_join()たが、 内で動作しないようですthread_func()。誰かが私を正しい方向に向けることができますか? それとも、不可能なことをしようとしていますか?

編集: i と t はローカル変数thread_func()です..言及するのを忘れました..

EDIT2:私の説明はあまり明確ではないかもしれません... main()(コードには表示されていません)でいくつかのスレッドを作成し、各スレッドはthread_func(). 内側の for ループをスレッド間で分割しました。ただし、外側の for ループの次の t ステップに進む前に、次の t ステップの結果は現在の t ステップの結果に依存するため、すべてのスレッドが現在の t ステップを終了していることを確認する必要があります。どうやってやるの?それが今より理にかなっていることを願っています..

4

1 に答える 1

1

スレッドが一般的にどのように機能するかについて、多少混乱しているようです。

実際には、thread_func()作成したさまざまなスレッド間で共有されることはありません。各スレッドには独自のコンテキストがあります。それらのすべてが実行中であってもthread_func()、すべてがローカルである限り、それらのいずれも他の計算を台無しにしません。

同時アクセスについて心配する必要がある唯一のケースは、共有データ (グローバル変数など) の場合です。この場合、通常はミューテックスまたはセマフォを使用します。について読んでpthread_mutex_tsem_t

更新:と が何であるかを正確に指定していないため、それらはローカル変数であると想定しましたtiそれらがグローバルである場合、ミューテックスを使用してこれらの変数へのアクセスを同期する必要があります。tまたはのような意味のない名前でグローバル変数を呼び出すことiは、一般的に悪い習慣であることに注意してください。

更新 2:あなたの編集により、あなたが本当に望んでいるものを理解できました。現時点で考えられる唯一の解決策は、tすべてのスレッドに対して機能するグローバル変数を用意する必要があるということです。と呼びましょうstepstepすべてのスレッドがそれを読み取り、現在の反復が何であるかを知ることができるため、グローバルです。ただし、この変数への同時アクセスを調整するには、前述のようにミューテックスが必要です。

基本的なレイアウトは次のようになります。スレッドは、そのコンテキスト内で実行された最後の反復を格納します。step別のスレッドによって更新されたかどうかを確認するために繰り返しテストしています。それが起こると、forループの実行を開始します (ループのi = start; ...実行後、スレッドはそれがこの反復の最後のループであるかどうかをテストする必要があります。そうである場合は、グローバル値をインクリメントする必要がありますstep(このとき、の新しい値を待ってスタックしていたスレッドはすべてstep前進します)。

私たちが最後のスレッドであるかどうかをテストすることは、作成したスレッドの数を何らかの形で知っていることを意味します。これをパラメーターとして渡すか、定数として定義できます。として定義されていると仮定しTHREADS_NOます。

結果として、現在の反復を終了したスレッドの数を知るために、グローバル カウンターとミューテックスも必要になります。

したがって、ファイルは次のようになります。

pthread_mutex_t step_mutex;
pthread_mutex_t counter_mutex;

int step;
int counter;

void* thread_func(void* a) {
    int t, i, curr_t;
    struct type *b = (struct type*)a;
    int start = b->start;
    int stop = b->stop;
    t = -1;
    curr_t = 0;
    while (1) {
        while (curr_t == t) {
            /* Wait for the next step */
            pthread_mutex_lock(&step_mutex);
            curr_t = step;
            pthread_mutex_unlock(&step_mutex);      
        }
        /* New value for t arrived */
        t = curr_t;
        if (t >= 1000) {
            break;
        }
        for (i = start; i < stop; i++) {
            /***** Calculation*****/
        }
        pthread_mutex_lock(&counter_mutex);
        if (++counter == THREADS_NO) {
            counter = 0;
            pthread_mutex_lock(&step_mutex);
            step++;
            pthread_mutex_unlock(&step_mutex);
        }
        pthread_mutex_unlock(&counter_mutex);
    }   
    return NULL;
}

おそらく でスレッドを作成する前に、両方のミューテックスを初期化する必要がありますmain()

pthread_mutex_init(&step_mutex, NULL);
pthread_mutex_init(&counter_mutex, NULL);

そして、仕事が終わったら、それらを破棄することを忘れないでください:

pthread_mutex_destroy(&step_mutex);
pthread_mutex_destroy(&counter_mutex);

エラーが発生する可能性があるため、ミューテックスを初期化、ロック、および破棄する関数の戻り値をテストする必要があることに注意してください。

最後に、これが本当に必要かどうかを検討してください。プログラムまたはアルゴリズムを再設計する必要があるかもしれません。このアプローチはあまり効率的ではありません。スレッドは新しい値を繰り返しテストするために CPU サイクルを浪費するからですstep(これはビジー待機と呼ばれます)。「私たちはまだそこにいますか?私たちはまだそこにいますか?私たちはまだそこにいますか?」のようなものです...あまり賢くはありません。

注:このコードをテストできませんでした。あなたが投稿したコードは、何を達成しようとしているのかを知るのを少し難しくしているので、これが完全に機能するかどうかはわかりません.

于 2013-11-08T16:33:02.367 に答える