3

C POSIX スレッドのミューテックス/条件に予期しない動作が見られます。これは、mutex 変数と条件変数が構造体 (場合によっては機能する) のグローバル スコープ (機能する) に設定されているかどうかによって異なります。

Mac でプログラミングしてから、Linux マシンで同じコードを実行しています。両方のマシンで期待どおりに動作するこの例からコードをコピーしました: http://publib.boulder.ibm.com/infocenter/iseries/v7r1m0/index.jsp?topic=%2Fapis%2Fusers_73.htm この例には、pthread_mutex_tそしてpthread_cond_tグローバルスコープで:

pthread_cond_t      cond  = PTHREAD_COND_INITIALIZER;
pthread_mutex_t     mutex = PTHREAD_MUTEX_INITIALIZER;
...
pthread_mutex_lock(&mutex);
...

ただし、cond とミューテックスを構造体に格納するようにこれを変更すると、Mac では機能しますが、Linux では機能しません。

私が行った変更の概要は次のとおりです。

typedef struct _test_data_t {
  pthread_mutex_t cond;
  pthread_cond_t mutex;
} test_data_t;
...
pthread_mutex_lock(&(test_data->mutex));
...

Macで得られる出力は次のとおりです(これは機能します)

スレッドを 5 つ作成する
スレッドがブロックされました
スレッドがブロックされました
スレッドがブロックされました
スレッドがブロックされました
スレッドがブロックされました
待機中のすべてのスレッドを起こします...
スレッドとクリーンアップを待つ
メイン完成

これはLinuxでの出力です(これは機能しません)

スレッドを 5 つ作成する
スレッドがブロックされました // ここで永久にハングします。他のスレッドはミューテックスをロックできません

なぜこれが起こっているのか誰にも分かりますか?私は C の専門家ではないので、グローバル変数の使用から構造体変数への切り替えで何が起こったのかわかりません。

よろしくお願いします。


コードは次のとおりです (簡潔にするために一部のエラー チェックを省略しています)。

typedef struct _test_data_t {
  int conditionMet;
  pthread_mutex_t cond;
  pthread_cond_t mutex;
} test_data_t;

void *threadfunc(void *parm)
{
  int           rc;
  test_data_t *test_data = (test_data_t *) parm;

  rc = pthread_mutex_lock((pthread_mutex_t *)&(test_data->mutex));

  while (!test_data->conditionMet) {
    printf("Thread blocked\n");
    rc = pthread_cond_wait(&test_data->cond, &test_data->mutex);
  }

  rc = pthread_mutex_unlock(&test_data->mutex);
  return NULL;
}

void runThreadTest() {

  int NTHREADS = 5;

  int                   rc=0;
  int                   i;

  // Initialize mutex/condition.
  test_data_t test_data;
  test_data.conditionMet = 0;
  rc = pthread_mutex_init(&test_data.mutex, NULL);
  rc = pthread_cond_init(&test_data.cond, NULL);

  // Create threads.
  pthread_t             threadid[NTHREADS];

  printf("Create %d threads\n", NTHREADS);
  for(i=0; i<NTHREADS; ++i) {
    rc = pthread_create(&threadid[i], NULL, threadfunc, &test_data);
  }

  sleep(5);
  rc = pthread_mutex_lock(&test_data.mutex);

  /* The condition has occurred. Set the flag and wake up any waiting threads */
  test_data.conditionMet = 1;
  printf("Wake up all waiting threads...\n");
  rc = pthread_cond_broadcast(&test_data.cond);

  rc = pthread_mutex_unlock(&test_data.mutex);

  printf("Wait for threads and cleanup\n");
  for (i=0; i<NTHREADS; ++i) {
    rc = pthread_join(threadid[i], NULL);
  }

  pthread_cond_destroy(&test_data.cond);
  pthread_mutex_destroy(&test_data.mutex);

  printf("Main completed\n");
}
4

1 に答える 1

2

問題は、指定されたメンバーmutexが であり、指定さpthread_cond_tれたメンバーが であるというcondことですpthread_mutex_t。不要なはずのキャストが、その事実を隠しているのかもしれません。

typedef struct _test_data_t {
  int conditionMet;
  pthread_mutex_t cond; // <-- poorly named
  pthread_cond_t mutex; // <-- poorly named
} test_data_t;

スレッド関数の次の行はキャストを必要としません。

  rc = pthread_mutex_lock((pthread_mutex_t *)&(test_data->mutex));

ただし、キャストを持たない呼び出しがいくつかあります (そのため、コンパイラはそれらについて大声で文句を言う必要があります)。これは誤植ではないかと思い始めています。

于 2012-11-24T00:50:17.710 に答える