¿Cuándo usar pthread exit () y cuándo usar pthread join () en Linux?


Soy nuevo en pthreads, y estoy tratando de entenderlo. Vi algunos ejemplos como los siguientes.

Pude ver que el main() está bloqueado por la API pthread_exit(), y he visto ejemplos donde la función principal está bloqueada por la API pthread_join(). No soy capaz de entender cuándo usar qué?

Me refiero al siguiente sitio - https://computing.llnl.gov/tutorials/pthreads / . No puedo obtener el concepto de cuándo usar pthread_join() y cuándo usar pthread_exit().

¿Puede alguien por favor explicar? También, un buen enlace tutorial para pthreads será apreciado.

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

void *PrintHello(void *threadid)
{
   long tid;
   tid = (long)threadid;
   printf("Hello World! It's 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);

Se dio cuenta de una cosa más, es decir,

pthread_cancel(thread);
pthread_join(thread, NULL);

A veces, desea cancelar el subproceso mientras se ejecuta. Puedes hacer esto usando pthread_cancel (thread);. Sin embargo, recuerde que debe habilitar el soporte de cancelación de pthread. Además, un código de limpieza tras la cancelación.

thread_cleanup_push(my_thread_cleanup_handler, resources);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);

static void my_thread_cleanup_handler(void *arg)
{
  // free
  // close, fclose
}
Author: dexterous_stranger, 2013-12-29

8 answers

Como se explica en las documentaciones de openpub,

pthread_exit() saldrá del hilo que lo llama.

En su caso, ya que el main lo llama, main thread terminará mientras que sus subprocesos generados continuarán ejecutándose. Esto se utiliza sobre todo en los casos en que el el hilo principal solo es necesario para generar hilos y dejar que los hilos hagan su trabajo

pthread_join suspenderá la ejecución del subproceso que lo ha llamado a menos que el subproceso de destino terminates

Esto es útil en los casos en los que desea esperar a que el/los hilo / s termine antes de continuar procesamiento en hilo principal.

Un buen enlace para lo basico

 32
Author: Suvarna Pattayil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-01 11:02:58

pthread_exit termina el subproceso de llamada mientras que pthread_join suspende la ejecución del subproceso de llamada hasta que los subprocesos de destino completen la ejecución.

Están bastante bien explicados en detalle en la documentación de open group:

 11
Author: Alok Save,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-29 10:49:53

Ambos métodos aseguran que su proceso no termine antes de que todos sus subprocesos hayan terminado.

El método join hace que su subproceso de la función main espere explícitamente a que todos los subprocesos se "unan".

El método pthread_exit termina la función main y el hilo de una manera controlada. main tiene la particularidad de que terminar main de lo contrario sería terminar todo el proceso incluyendo todos los demás hilos.

Para que esto funcione, tienes que estar seguro que ninguno de sus subprocesos está usando variables locales que se declaran dentro de la función main. La ventaja de ese método es que su main no tiene que conocer todos los hilos que se han iniciado en su proceso, por ejemplo, porque otros hilos han creado nuevos hilos de los que main no sabe nada.

 7
Author: Jens Gustedt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-29 12:15:24

No necesita ninguna llamada para pthread_exit(3) en tu código particular.

En general, el hilo main debe no llamar pthread_exit, pero a menudo debe llamar pthread_join(3) para esperar para que otro hilo termine.

En su función PrintHello, no necesita llamar a pthread_exit porque está implícita después de regresar de ella.

Así que tu código debería ser:

void *PrintHello(void *threadid)  {
  long tid = (long)threadid;
  printf("Hello World! It's 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);
      }
   }
}
 2
Author: Basile Starynkevitch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-29 11:17:55

La API pthread_exit ()

Como ya se ha comentado, se utiliza para la terminación del subproceso de llamada. Después de una llamada a esa función, se inicia un mecanismo de limpieza complicado. Cuando se completa el hilo se termina. La API pthread_exit() también se llama implícitamente cuando se produce una llamada a la rutina return () en un subproceso creado por pthread_create (). En realidad, una llamada a return() y una llamada a pthread_exit() tienen el mismo impacto, siendo llamada desde un hilo creado por pthread_create ().

Es muy importante distinguir el hilo inicial, creado implícitamente cuando se inicia la función main (), y los hilos creados por pthread_create(). Una llamada a la rutina return() desde la función main() invoca implícitamente la llamada al sistema exit () y todo el proceso termina. No se inicia ningún mecanismo de limpieza de hilo. Una llamada a la pthread_exit () desde la función main () hace que el mecanismo de limpieza se inicie y cuando termine su trabajo el hilo inicial termina.

Lo que le sucede a todo el proceso (y a otros subprocesos) cuando se llama a pthread_exit() desde la función main() depende de la implementación de PTHREAD. Por ejemplo, en la implementación de IBM OS/400, se termina todo el proceso, incluidos otros subprocesos, cuando se llama a pthread_exit() desde la función main (). Otros sistemas pueden comportarse de manera diferente. En la mayoría de las máquinas Linux modernas, una llamada a pthread_exit () desde el subproceso inicial no termina todo el proceso hasta que terminación de hilos. Tenga cuidado usando pthread_exit() desde main(), si desea escribir una aplicación portable.

La API pthread_join ()

Es una forma conveniente de esperar la terminación de un hilo. Puedes escribir tu propia función que espera la terminación de un subproceso, quizás más adecuada para tu aplicación, en lugar de usar pthread_join (). Por ejemplo, puede ser una función basada en la espera de variables condicionales.

Recomendaría para leer un libro de David R. Butenhof "Programación con hilos POSIX". Explica muy bien los temas discutidos (y cosas más complicadas) (aunque algunos detalles de implementación, como el uso de pthread_exit en la función principal, no siempre se reflejan en el libro).

 2
Author: MichaelGoren,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-02 09:41:14

pthread_exit() terminará el subproceso de llamada y saldrá de eso (pero los recursos utilizados por el subproceso de llamada no se liberan al sistema operativo si no se separa del subproceso principal.)

pthrade_join() esperará o bloqueará el subproceso de llamada hasta que el subproceso de destino no se termine. En simple word esperará a salir del hilo de destino.

En su código, si pone sleep(o delay) en la función PrintHello antes de pthread_exit(), entonces el hilo principal puede ser exit y terminar el proceso completo, Aunque su PrintHello la función no se ha completado, terminará. Si usas la función pthrade_join() en main antes de llamar a pthread_exit() desde main, bloqueará el hilo principal y esperará a completar el hilo de llamada (PrintHello).

 2
Author: Abhitesh khatri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-18 16:17:41

Hmm.

POSIX pthread_exit descripción de 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.

Lo que parece contrario a la idea de que las variables locales del hilo main() permanecerán accesibles.

 1
Author: jim mcnamara,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-29 16:31:13

Usando pthread_exit en el hilo principal(en lugar de pthread_join), dejará el hilo principal en estado extinto(zombi). Dado que no se usa pthread_join, otros subprocesos enlazables que se terminen también permanecerán en el estado zombie y causarán una fuga de recursos.

   Failure to join with a thread that is joinable (i.e., one that is not
   detached), produces a "zombie thread".  Avoid doing this, since each
   zombie thread consumes some system resources, and when enough zombie
   threads have accumulated, it will no longer be possible to create new
   threads (or processes).

Otro punto es mantener el subproceso principal en el estado extinto, mientras que otros subprocesos se ejecutan pueden causar problemas dependientes de la implementación en varias condiciones, como si los recursos se asignan en main el hilo o las variables que son locales al hilo principal se utilizan en otros hilos.

Además, todos los recursos compartidos se liberan solo cuando el proceso sale, no está ahorrando ningún recurso. Por lo tanto, creo que se debe evitar usar pthread_exit en lugar de pthread_join.

 0
Author: Preeti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-26 11:43:38