c++ multithreading

c++ - ¿Por qué una llamada debe unirse() o separar() antes de la destrucción de subprocesos?



multithreading (3)

No entiendo por qué cuando se destruye un std::thread debe estar en estado join () o detach ().

Unirse espera a que el hilo termine, y la separación no. Parece que hay algún estado intermedio que no entiendo. Porque entiendo que unirse y separar son complementarios: si no llamo join (), entonces detach () es el valor predeterminado.

Póngalo de esta manera, digamos que está escribiendo un programa que crea un subproceso y solo más adelante en la vida de este subproceso que llama join (), por lo que hasta que llame unir el subproceso se ejecutaba básicamente como si se hubiera desasociado, ?

Lógicamente, detach () debe ser el comportamiento predeterminado de los subprocesos porque esa es la definición de qué subprocesos son, se ejecutan en paralelo, independientemente de otros subprocesos.

Entonces, cuando el objeto de hilo se destruye, ¿por qué se llama a terminate ()? ¿Por qué no puede la norma simplemente tratar el hilo como separado?

No entiendo la razón detrás de la finalización de un programa cuando no se llamó a join () o desvinculado () antes de que se destruyera el hilo. ¿Cuál es el propósito de esto?


Es posible que desee que un subproceso se limpie completamente después de sí mismo cuando se hace sin dejar rastros. Esto significaría que podrías comenzar un hilo y luego olvidarte de él.

Pero es posible que también desee poder administrar un subproceso mientras se estaba ejecutando y obtener el valor de retorno que proporcionó cuando se realizó. En este caso, si un subproceso se limpia después de sí mismo cuando se realizó, su intento de administrarlo podría causar un bloqueo porque estaría accediendo a un identificador que podría no ser válido. Y para verificar el valor de retorno cuando finaliza el subproceso, el valor de retorno debe almacenarse en algún lugar, lo que significa que el hilo no se puede limpiar completamente porque el lugar donde se almacena el valor de retorno debe quedar alrededor.

En la mayoría de los marcos, por defecto, obtienes la segunda opción. Puede administrar el hilo (interrumpiéndolo, enviándole señales, uniéndolo o lo que sea) pero no puede limpiarse después de él. Si prefiere la primera opción, hay una función para obtener ese comportamiento (desvinculación) pero eso significa que es posible que no pueda acceder al subproceso porque puede o no continuar existiendo.


Técnicamente, la respuesta es "porque la especificación lo dice", pero esa es una respuesta obtusa. No podemos leer las mentes de los diseñadores, pero aquí hay algunos problemas que pueden haber contribuido:

Con los pthreads de POSIX, los subprocesos secundarios se deben unir después de que hayan salido o, de lo contrario, seguirán ocupando los recursos del sistema (como una entrada de la tabla de procesos en el kernel). Esto se hace a través de pthread_join() . Windows tiene un problema un tanto análogo si el proceso mantiene un HANDLE en el subproceso secundario; aunque Windows no requiere una unión completa, el proceso aún debe llamar a CloseHandle() para liberar su refcount en el hilo.

Dado que std::thread es una abstracción multiplataforma, está limitado por el requisito POSIX que requiere la unión.

En teoría, std::thread destructor podría haber llamado pthread_join() lugar de lanzar una excepción, pero eso (subjetivamente) puede aumentar el riesgo de interbloqueo. Mientras que un programa escrito correctamente sabría cuándo insertar la unión en un momento seguro.

Ver también:


Te estás confundiendo porque estás confundiendo el objeto std::thread con el hilo de ejecución al que se refiere. Un objeto std::thread es un objeto C ++ (un grupo de bytes en la memoria) que actúa como una referencia a un hilo de ejecución. Cuando llama a std::thread::detach lo que sucede es que el objeto std::thread está "separado" del subproceso de ejecución; ya no hace referencia a (ningún) subproceso de ejecución, y el subproceso de ejecución continúa ejecutándose independientemente. Pero el objeto std::thread todavía existe, hasta que se destruye.

Cuando se completa un subproceso de ejecución, almacena su información de salida en el objeto std::thread que se refiere a él, si hay uno (si se separó, entonces no hay uno, por lo que la información de salida simplemente se desecha). ) No tiene ningún otro efecto en el objeto std::thread , en particular, el objeto std::thread no se destruye y continúa existiendo hasta que alguien más lo destruya.