Подтвердить что ты не робот

Когда использовать pthread_exit() и когда использовать pthread_join() в Linux?

Я новичок в pthreads, и я пытаюсь это понять. Я видел несколько примеров:

Я мог видеть, что main() заблокирован API pthread_exit(), и я видел примеры, где основная функция блокируется API pthread_join(). Я не могу понять, когда использовать что?

Я имею в виду следующий сайт - https://computing.llnl.gov/tutorials/pthreads/. Я не могу понять, когда использовать pthread_join() и когда использовать pthread_exit().

Может кто-нибудь объяснить? Кроме того, будет оценена хорошая учебная ссылка для pthreads.

#include <pthread.h>
#include <stdio.h>
#define NUM_THREADS     5

void *PrintHello(void *threadid)
{
   long tid;
   tid = (long)threadid;
   printf("Hello World! It me, thread #%ld!\n", tid);
   pthread_exit(NULL);
}

int main (int argc, char *argv[])
{
   pthread_t threads[NUM_THREADS];
   int rc;
   long t;
   for(t=0; t<NUM_THREADS; t++){
      printf("In main: creating thread %ld\n", t);
      rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
      if (rc){
         printf("ERROR; return code from pthread_create() is %d\n", rc);
         exit(-1);
      }
   }

   /* Last thing that main() should do */
   pthread_exit(NULL);
4b9b3361

Ответ 1

Как объясняется в документах openpub,

pthread_exit() выйдет из потока, который его вызывает.

В вашем случае, поскольку основные вызовы его, основной поток будет завершен, тогда как ваши порожденные потоки будут продолжать выполняться. Это в основном используется в тех случаях, когда основной поток требуется только для создания потоков и оставления нитей для выполнения своей работы.

pthread_join приостанавливает выполнение потока, который вызвал его, если целевой поток не завершает

Это полезно в тех случаях, когда вы хотите дождаться завершения потока /s до обработка в основном потоке.

Хорошая ссылка для основ

Ответ 2

pthread_exit завершает вызывающий поток, а pthread_join приостанавливает выполнение вызывающего потока до тех пор, пока целевые потоки не завершат выполнение.

Они хорошо описаны в документации открытой группы:

Ответ 3

Оба метода гарантируют, что ваш процесс не завершится до того, как все ваши потоки закончились.

В методе объединения ваш поток функции main явно ожидает всех потоков, которые должны быть "соединены".

Метод pthread_exit завершает вашу функцию main и поток контролируемым образом. main имеет особенность, что завершение main в противном случае приведет к завершению всего процесса, включая все остальные потоки.

Чтобы это сработало, вы должны быть уверены, что ни один из ваших потоков не использует локальные переменные, объявленные внутри них main. Преимущество этого метода в том, что ваш main не должен знать все потоки, которые были запущены в вашем процессе, например, потому что другие потоки сами создали новые потоки, о которых main ничего не знает.

Ответ 4

Вам не нужны вызовы pthread_exit(3) в вашем конкретном коде.

В общем случае поток main не должен вызывать pthread_exit, но часто следует называть pthread_join(3), чтобы ждать какой-либо другой поток закончить.

В вашей функции PrintHello вам не нужно вызывать pthread_exit, потому что она неявна после возвращения из нее.

Итак, ваш код должен быть:

void *PrintHello(void *threadid)  {
  long tid = (long)threadid;
  printf("Hello World! It me, thread #%ld!\n", tid);
  return threadid;
}

int main (int argc, char *argv[]) {
   pthread_t threads[NUM_THREADS];
   int rc;
   intptr_t t;
   // create all the threads
   for(t=0; t<NUM_THREADS; t++){
     printf("In main: creating thread %ld\n", (long) t);
     rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
     if (rc) { fprintf(stderr, "failed to create thread #%ld - %s\n",
                                (long)t, strerror(rc));
               exit(EXIT_FAILURE);
             };
   }
   pthread_yield(); // useful to give other threads more chance to run
   // join all the threads
   for(t=0; t<NUM_THREADS; t++){
      printf("In main: joining thread #%ld\n", (long) t);
      rc = pthread_join(&threads[t], NULL);
      if (rc) { fprintf(stderr, "failed to join thread #%ld - %s\n",
                                (long)t, strerror(rc));
               exit(EXIT_FAILURE);
      }
   }
}

Ответ 5

API pthread_exit()

как уже было отмечено, используется для завершения вызывающего потока. После вызова этой функции запускается сложный механизм очистки. Когда он завершается, поток прекращается. API pthread_exit() также называется неявным, когда вызов функции return() происходит в потоке, создаваемом pthread_create(). На самом деле вызов return() и вызов pthread_exit() имеют одинаковое воздействие, вызываемое из потока, созданного pthread_create().

Очень важно различать начальный поток, неявно созданный при запуске функции main(), и потоки, созданные pthread_create(). Вызов функции return() из функции main() неявно вызывает системный вызов exit(), и весь процесс завершается. Механизм очистки нитей не запускается. Вызов функции pthread_exit() из функции main() приводит к запуску механизма очистки, и когда он завершает свою работу, исходный поток завершается.

Что происходит со всем процессом (и другими потоками), когда pthread_exit() вызывается из функции main(), зависит от реализации PTHREAD. Например, при реализации IBM OS/400 весь процесс завершается, включая другие потоки, когда pthread_exit() вызывается из функции main(). Другие системы могут вести себя по-разному. На большинстве современных Linux-машин вызов pthread_exit() из начального потока не завершает весь процесс до тех пор, пока все потоки не прекратятся. Будьте осторожны, используя pthread_exit() из main(), если вы хотите написать переносное приложение.

API pthread_join()

- удобный способ дождаться завершения потока. Вы можете написать свою собственную функцию, которая ждет завершения потока, возможно, более подходящего для вашего приложения, вместо использования pthread_join(). Например, это может быть функция, основанная на ожидании условных переменных.

Я бы рекомендовал прочитать книгу David R. Butenhof "Программирование с потоками POSIX". Он объясняет обсуждаемые темы (и более сложные вещи) очень хорошо (хотя некоторые детали реализации, такие как использование pthread_exit в основной функции, не всегда отражены в книге).

Ответ 6

pthread_exit() завершает вызывающий поток и выходит из него (но ресурсы, используемые вызовом потока, не выводятся в операционную систему, если они не отсоединены от основного потока.)

pthrade_join() будет ждать или блокировать вызывающий поток до тех пор, пока целевой поток не будет прерван. В простом слове он будет ждать выхода из целевого потока.

В вашем коде, если вы положили sleep (или задержку) в PrintHello перед pthread_exit(), тогда основной поток может быть завершен и завершить полный процесс. Хотя ваша функция PrintHello не завершена, она будет завершена. Если вы используете функцию pthrade_join() в главном, прежде чем вызывать pthread_exit() из основного, она заблокирует основной поток и дождитесь завершения вашего вызывающего потока (PrintHello).

Ответ 7

Хм.

POSIX pthread_exit описание http://pubs.opengroup.org/onlinepubs/009604599/functions/pthread_exit.html:

After a thread has terminated, the result of access to local (auto) variables of the thread is 
undefined. Thus, references to local variables of the exiting thread should not be used for 
the pthread_exit() value_ptr parameter value.

Что противоречит идее, что локальные переменные потока main() остаются доступными.