Почему pthread_join не закрывает массив потоков должным образом в этом примере?

#c #pthreads

#c #pthreads

Вопрос:

Я пытаюсь научить себя потоковой обработке pthreads. У меня есть следующий исходный код, который компилируется и запускается должным образом:

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

#define PTHREAD_COUNT 10
#define FREQ 5

void *thread_function(void *arg) {
  int *incoming = (int *)arg;
  int freqIdx;

  for (freqIdx = 0; freqIdx < FREQ; freqIdx  )
    fprintf(stdout, "Hello, world (thread %d)n", *incoming);

  return NULL;
}

int main(int argc, char **argv) {
  pthread_t thread_IDs[PTHREAD_COUNT];
  void *exit_status;
  int threadIdx;

  for (threadIdx = 0; threadIdx < PTHREAD_COUNT; threadIdx  ) {
    pthread_create(amp;thread_IDs[threadIdx], NULL, thread_function, amp;threadIdx);
    pthread_join(thread_IDs[threadIdx], amp;exit_status);
  }

  return 0;
}
  

Я получаю следующий результат:

 Hello, world (thread 0)
Hello, world (thread 0)
Hello, world (thread 0)
Hello, world (thread 0)
Hello, world (thread 0)
Hello, world (thread 1)
...
Hello, world (thread 9)
  

Если я pthread_create создаю массив pthread_t типов в цикле, а затем pthread_join в отдельном цикле, тогда все терпит неудачу:

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

#define PTHREAD_COUNT 10
#define FREQ 5

void *thread_function(void *arg) {
  int *incoming = (int *)arg;
  int freqIdx;

  for (freqIdx = 0; freqIdx < FREQ; freqIdx  )
    fprintf(stdout, "Hello, world (thread %d)n", *incoming);

  return NULL;
}

int main(int argc, char **argv) {
  pthread_t thread_IDs[PTHREAD_COUNT];
  void *exit_status;
  int threadIdx;

  /* here I split the thread _create and _join steps into separate loops */

  for (threadIdx = 0; threadIdx < PTHREAD_COUNT; threadIdx  )
    pthread_create(amp;thread_IDs[threadIdx], NULL, thread_function, amp;threadIdx);

  for (threadIdx = 0; threadIdx < PTHREAD_COUNT; threadIdx  )
    pthread_join(thread_IDs[threadIdx], amp;exit_status);

  return 0;
}
  

Результат этого совершенно неверен. Вместо получения пяти fprintf операторов из каждого потока я получаю один или два, скажем, из потоков 2 и 3, и примерно от 20 до 25 Hello, world операторов из потока 0.

Почему это не удается?

Ответ №1:

Одна из проблем, которую я вижу, заключается в том, что вы даете ему адрес локальной переменной threadIdx . Когда вы изменяете его в цикле, значение, которое видит поток, также изменяется. Таким образом, значение threadIdx не будет правильным.

Во 2-м цикле вы снова устанавливаете threadIdx равным 0 и ждете завершения потоков, что объясняет, почему вы видите, что многие из них печатают поток 0 вместо этого.

Вы можете просто передать threadIdx, а затем интерпретировать аргументы void * вместо этого как int (потому что sizeof(int) <= sizeof(void *) и обычно гарантируется на большинстве машин), и вы должны получить правильный вывод.

Ответ №2:

Как указывали другие, ваша проблема заключается в разделении одной threadIdx переменной между всеми потоками. Один из способов исправить это — создать одну переменную для каждого потока:

 int threadIdx;
int indexes[PTHREAD_COUNT];

for (threadIdx = 0; threadIdx < PTHREAD_COUNT; threadIdx  ) {
    indexes[threadIdx] = threadIdx;
    pthread_create(amp;thread_IDs[threadIdx], NULL, thread_function, amp;indexes[threadIdx]);
}
  

Ответ №3:

Вы передаете указатель на одну и ту же threadIdx переменную всем потокам.