Si tengo un programa ejecutándose con subprocesos y llamo a fork() en un sistema basado en Unix, ¿se copian los subprocesos? Sé que la memoria virtual del proceso actual se copia 1:1 en el nuevo proceso generado. Sé que los hilos tienen su propia pila en la memoria virtual de un proceso. Por lo tanto, al menos la pila de subprocesos también debe copiarse. Sin embargo, no sé si hay algo más en los subprocesos que no reside en la memoria virtual y, por lo tanto, NO se copia. Si no lo hay, ¿los dos procesos comparten los hilos o son copias independientes?
El proceso hijo se crea con un único subproceso, el que llama a fork(). Todo el espacio de direcciones virtuales del padre se replica en el hijo, incluidos los estados de mutexes, variables de condición y otros objetos pthreads; el uso de pthread_atfork(3) puede ser útil para lidiar con los problemas que esto puede causar.
Los hilos no se copian en fork() . La especificación POSIX dice (el énfasis es mío):
bifurcación - crea un nuevo proceso
Un proceso debe ser creado con un solo hilo . Si un proceso de subprocesos múltiples llama a fork(), el nuevo proceso contendrá una réplica del subproceso de llamada y su espacio de direcciones completo, posiblemente incluidos los estados de mutexes y otros recursos. En consecuencia, para evitar errores, el proceso secundario solo puede ejecutar operaciones seguras de señal asíncrona hasta que se llame a una de las funciones exec.
Para sortear este problema, existe una función pthread_atfork() para ayudar.
De la bifurcación de la edición 7, 2018 de The Open Group Base Specifications:
Se debe crear un proceso con un único subproceso. Si un proceso de subprocesos múltiples llama a fork() , el nuevo proceso contendrá una réplica del subproceso de llamada y todo su espacio de direcciones, posiblemente incluidos los estados de mutexes y otros recursos. En consecuencia, para evitar errores, el proceso secundario solo puede ejecutar operaciones seguras de señal asíncrona hasta que se llame a una de las funciones exec .
Cuando la aplicación llama a fork() desde un controlador de señal y cualquiera de los controladores de bifurcación registrados por pthread_atfork() llama a una función que no es segura para señales asíncronas, el comportamiento no está definido.
Originalmente, la "bifurcación" se lograba escribiendo la tarea en el disco y luego, en lugar de leer en un subproceso diferente (que se haría si se intercambiaba la tarea con una diferente), modificando la identificación de la tarea de la imagen aún en la memoria y continuando con su ejecución (como la nueva tarea). Esta fue una modificación muy simple del mecanismo básico de cambio de tareas, donde solo una tarea ocuparía la memoria RAM a la vez.
Por supuesto, a medida que la gestión de la memoria se volvió más elaborada, este esquema se modificó para adaptarse al nuevo entorno.