A2A
Esta es una pregunta un tanto compleja, porque está mezclando detalles de implementación en diferentes capas y porque es difícil usar una analogía de proceso, a menos que tenga una comprensión relativamente sustancial de la relación entre los procesos padre e hijo.
Comencemos con solo hilos, y el nivel en el que está llegando a cierta confusión.
Cuando se crea un hilo, se crea con ciertos atributos de hilo. Estos pueden especificarse antes de llamar a pthread_create
, o pueden estar predeterminados.
- ¿Por qué el parasitismo más puro es el más recompensado?
- ¿Qué son los estudios de gemelos en psicología?
- ¿Por qué amamos el olor de nuestro propio pedo pero no nos gusta el de los demás?
- ¿Cómo se puede explicar que las elecciones egoístas y terribles, como la infidelidad, son un síntoma de una crisis mental y no porque no amaron a la otra persona?
- ¿Qué ventaja evolutiva habría tenido la paranoia?
Uno de estos es si puede o no llamar a pthread_join
en el hilo en algún momento posterior en el tiempo. Este atributo es detachstate
.
El atributo detachstate
puede tomar uno de dos valores:
-
PTHREAD_CREATE_JOINABLE
– este es el valor predeterminado -
PTHREAD_CREATE_DETACHED
: esto se puede configurar
¿Cómo configura PTHREAD_CREATE_DETACHED
para que no se pueda PTHREAD_CREATE_DETACHED
un hilo? Hay dos maneras:
- La primera es configurar un valor
pthread_attr_t
y luego llamar apthread_attr_setdetachstate
con un parámetrodetachstate
dePTHREAD_CREATE_DETACHED
. Cuando posteriormente llamaspthread_create
, pasas estepthread_attr_t
apthread_create
.Esto establece que cuando se llama a
pthread_exit
en ese hilo, simplemente desaparecerá, en lugar de permanecer en un estado que se puede unir hasta quepthread_join
; es un error llamar apthread_detach
desde dicho hilo. - El segundo es creando el hilo que se puede unir; esto se logra al pasar no
pthread_attr_t
a la llamadapthread_create
, o al establecer un atributo, pero dejando el valor de detachstate como predeterminado, o llamando explícitamente apthread_attr_setdetachstate
en el atributo con un parámetro dedetachstate
dePTHREAD_CREATE_JOINABLE
. A menos que haya modificado previamente el atributo, este será el predeterminado de todos modos.Más tarde, usted llama a
pthread_detach
en el hilo para separarlo explícitamente. Es un comportamiento indefinido, generalmente un error, llamar apthread_detach
en un subproceso ya separado. Si bien un subproceso puede llamar apthread_detach
en sí mismo, esto generalmente confunde o da como resultado un error en un subproceso que luego espera poder llamar apthread_join
en el subproceso.Esto establece que el hilo simplemente desaparecerá, en lugar de permanecer en un estado que se puede unir.
Con respecto a los procesos, y los grupos de procesos:
- Un hilo separado es análogo a un líder de grupo de procesos. Un líder de grupo de procesos no es recuperable por un proceso principal, ya que el proceso principal está en otro grupo de procesos.
- Un hilo que se puede unir es análogo a un proceso hijo en el grupo de procesos del padre, para el cual el padre es el líder del grupo de procesos, y el proceso hijo es simplemente un proceso dentro del grupo.
Una llamada a pthread_join
bloqueará el subproceso de llamada hasta que el subproceso de destino pueda unirse, o hasta que el proceso salga, o hasta que se llame a pthread_cancel
en el subproceso bloqueado (es un punto de cancelación).
Por lo tanto, un pthread_join
es análogo a una llamada a waitpid
con un valor pid
positivo, para no coincidir con cualquier comodín y un valor de argumento de options
de 0, para realizar el bloqueo de la llamada. No hay que esperar para pthread_join
través de un comodín – para cualquier subproceso que sale, en lugar de un subproceso que sale, a diferencia de waitpid
.
Aquí hay unos ejemplos. He omitido la comprobación de errores, para mayor claridad.
Creando un hilo que se puede unir:
pthread_t new_thread; void * new_thread_exit_status; // Crear un hilo con atributos por defecto; la amenaza // comienza la ejecución en la función 'my_thread_main' // lo que no tiene argumento pthread_create (& new_thread, NULL, my_thread_main, 0); ... // Únete al hilo creado previamente, cosechando la salida. // estado en un valor; típicamente este es un int pthread_join (new_thread, & new_thread_exit_status);
Creando un hilo separado (método # 1):
pthread_t new_thread; pthread_attr_t new_thread_attr; // Configurar el atributo separado pthread_attr_init (& new_thread_attr); pthread_attr_setdetachstate (& new_thread_attr, PTHREAD_CREATE_DETACHED); // Crear un hilo con atributo separado; la amenaza // comienza la ejecución en la función 'my_thread_main' // lo que no tiene argumento pthread_create (& new_thread, & new_thread_attr, my_thread_main, 0); ... // XXX No puedo llamar a pthread_join en new_thread
Creando un hilo separado (método # 2):
pthread_t new_thread; // Crear un hilo con atributos por defecto; la amenaza // comienza la ejecución en la función 'my_thread_main' // lo que no tiene argumento pthread_create (& new_thread, NULL, my_thread_main, 0); ... // new_thread se puede unir actualmente ... ... // Separar explícitamente new_thread pthread_detach (new_thread); ... // XXX No puedo llamar a pthread_join en new_thread
He omitido el caso donde se llama a pthread_detach desde my_thread_main; no solo lo considero propenso a errores, como se dijo anteriormente, sino que también lo considero una violación de API.
Esto se debe a que considero que es un mal diseño poner parte del control del ciclo de vida en el subproceso de creación, y parte de él en el subproceso creado (esta es la parte propensa a errores), y en segundo lugar porque no quiero proporcionar un implementación de my_thread_main
de my_thread_main
que se requeriría para demostrar los detalles de la implementación del diseño incorrecto.
Es probable que esta sea una respuesta tan completa como la que obtendrá.