4

マスター スレッドを最近開始した子スレッドに同期するのに問題があります。

私がやりたいことは次のとおりです。

  • マスタースレッドは新しい子スレッドを作成してブロックします
  • 子スレッドの開始と初期化 (時間がかかる場合があります)
  • 子スレッドが初期化されると、メイン スレッドが続行されます (そして 2 つのスレッドが並行して実行されます)。

私の最初の試みは次のようなものでした:

  typedef struct threaddata_ {
    int running;
  } threaddata_t;

  void*child_thread(void*arg) {
    threaddata_t*x=(threaddata_t)arg;
    /* ... INITIALIZE ... */
    x->running=1; /* signal that we are running */

    /* CHILD THREAD BODY */

    return 0;
  }

  void start_thread(void) {
    threaddata_t*x=(threaddata_t*)malloc(sizeof(threaddata_t));
    x->running=0;
    int result=pthread_create(&threadid, 0, child_thread, &running);
    while(!x->running) usleep(100); /* wait till child is initialized */

    /* MAIN THREAD BODY */
  }

メインスレッドをおそらく必要以上に長くスリープさせるので、私はこれがまったく好きではありませんでした。そこで、ミューテックスと条件を使用して、2回目の試行を行いました

  typedef struct threaddata_ {
    pthread_mutex_t x_mutex;
    pthread_cond_t  x_cond;
  } threaddata_t;

  void*child_thread(void*arg) {
    threaddata_t*x=(threaddata_t)arg;
    /* ... INITIALIZE ... */

    pthread_cond_signal(&x->x_cond); /* signal that we are running */

    /* CHILD THREAD BODY */

    return 0;
  }

  void start_thread(void) {
    threaddata_t*x=(threaddata_t*)malloc(sizeof(threaddata_t));
    pthread_mutex_init(&x->x_mutex, 0);
    pthread_cond_init (&x->x_cond , 0);

    pthread_mutex_lock(&x->x_mutex);
    int result=pthread_create(&threadid, 0, child_thread, &running);
    if(!result)pthread_cond_wait(&x->x_cond, &x->x_mutex);
    pthread_mutex_unlock(&x->x_mutex);

    /* MAIN THREAD BODY */
  }

これは最初の試行 (独自の待機ループをローリングするのではなく、適切なシグナルを使用) よりも正気のように見えましたが、これには競合状態が含まれていることがわかりました。状態)、メインスレッドをデッドロックします。

私のケースはそれほど珍しくないので、本当に簡単な解決策があるはずですが、今のところわかりません。

4

3 に答える 3

9

condvar/mutex ペアの適切な使用方法:

bool initialised = false;
mutex mt;
convar cv;

void *thread_proc(void *)
{
   ...
   mt.lock();
   initialised = true;
   cv.signal();
   mt.unlock();
}

int main()
{
   ...
   mt.lock();
   while(!initialised) cv.wait(mt);
   mt.unlock();
}

このアルゴリズムは、考えられる競合を回避します。ミューテックスがロックされたときに変更された複雑な条件を使用できます (単純な !initialized の代わりに)。

于 2012-07-13T14:07:43.493 に答える
2

バリアはうまく機能するはずです。コメントで Win32 のサポートの必要性について述べているため、バリアは最新の Win32 pthreads でサポートされているため、Win32 と *nix の間の移植性を得るために独自のラッパーを作成する必要はありません。

何かのようなもの:

typedef struct threaddata_ {
    pthread_barrier_t* pbarrier;
} threaddata_t;

void* child_thread(void*arg) {
    threaddata_t*x=(threaddata_t*)arg;
    /* ... INITIALIZE ... */

    int result = pthread_barrier_wait(x->pbarrier);

    /* CHILD THREAD BODY */

    return 0;
}

void start_thread(void) {
    pthread_barrier_t barrier;
    int result = pthread_barrier_init(&barrier, NULL, 2);

    threaddata_t*x=(threaddata_t*)malloc(sizeof(threaddata_t));
    x->pbarrier = &barrier;

    int result=pthread_create(&threadid, 0, child_thread, &x);

    result = pthread_barrier_wait(&barrier);
    /* child has reached the barrier */

    pthread_barrier_destroy(&barrier);  /* note: the child thread should not use    */
                                        /* the barrier pointer after it returns from*/
                                        /* pthread_barrier_wait()                   */


    /* MAIN THREAD BODY */
}

このソリューションの欠点は、子スレッドを不必要に一時的にブロックする可能性があることです。それが問題である場合は、 Dmitry Porohが言及した条件変数ソリューションが最適です。

于 2012-07-13T17:34:24.347 に答える
2

そのための正しいツールはsem_t. mainスレッドはそれらを初期化し、0新しく起動されたスレッドからトークンを受け取るまで待機します。

ところで、子スレッドがミューテックスをロックしていないため、ミューテックス/条件ソリューションには競合状態があります。

于 2012-07-13T14:01:49.853 に答える