Los conceptos del sistema operativo y APUE dicen
Con vfork (), el proceso primario se suspende y el proceso secundario usa el espacio de direcciones del primario. Debido a que vfork () no usa copia en escritura, si el proceso secundario cambia alguna página del espacio de direcciones del padre, las páginas alteradas serán visibles para el padre una vez que se reanude. Por lo tanto, vfork () debe usarse con precaución para garantizar que el proceso secundario no modifique el espacio de direcciones del principal.
vfork () está diseñado para usarse cuando el proceso hijo llama a exec () o exit () inmediatamente después de la creación.
¿Cómo entenderé la última oración?
Cuando un proceso hijo creado por vfork()
llamadas exec()
, ¿no exec()
modifica el espacio de direcciones del proceso padre al cargar el nuevo programa?
Cuando un proceso hijo creado por vfork()
llamadas exit()
, ¿ exit()
no modifica el espacio de direcciones del proceso padre al finalizar el hijo?
Tengo preferencia por Linux.
Gracias.
posix_spawn
. Es significativamente más difícil escribir el código correcto usandoposix_spawn
que con el viejofork
, y si lo intentas, puedes toparte con la pared de ladrillos de que no haya una acción o atributo de archivo que haga lo que necesitas hacer entrefork
yexec
. Y no se garantiza que tenga una eficiencia similar a la de vfork, por lo que ni siquiera resuelve el problema que la gente quiere que resuelva.posix_spawn
puede carecer de la funcionalidad que desea (puede resolver esto a través de un programa auxiliar intermedio, escrito en C o script de shell inline-on-cmdline), cualquier intento de lograr lo que desea convfork
invoca un comportamiento indefinido peligroso. La especificación paravfork
no permite llamar a funciones aleatorias para configurar el estado para que el hijo herede antesexecve
, y los intentos de hacerlo pueden dañar el estado del padre.posix_spawn
realiza aproximadamente lo mismo quevfork
en la mayoría de las condiciones. Los casos en los que hay una diferencia tienden a ser exactamente los casos en los quevfork
es altamente inseguro: donde hay controladores de señales instalados que deben evitar queposix_spawn
se ejecuten en el niño antes de la ejecución.Cuando llama
vfork()
, se crea un nuevo proceso y ese nuevo proceso toma prestada la imagen del proceso padre con la excepción de la pila. El proceso hijo recibe una nueva estrella de pila, sin embargo, no permitereturn
desde la función que llamóvfork()
.Mientras el niño se está ejecutando, el proceso padre se bloquea, ya que el niño tomó prestado el espacio de direcciones del padre.
Independientemente de lo que haga, todo lo que solo accede a la pila modifica solo la pila privada del niño. Sin embargo, si modifica los datos globales, esto modifica los datos comunes y, por lo tanto, también afecta al padre.
Las cosas que modifican los datos globales son, por ejemplo:
llamando a malloc () o gratis ()
usando stdio
modificar la configuración de la señal
modificando variables que no son locales a la función que llamó
vfork()
....
Una vez que llame
_exit()
(importante, nunca llameexit()
), el niño termina y el control se devuelve al padre.Si llama a cualquier función de la
exec*()
familia, se crea un nuevo espacio de direcciones con un nuevo código de programa, nuevos datos y una parte de la pila del padre (ver más abajo). Una vez que esto está listo, el niño ya no toma prestado el espacio de direcciones del niño, sino que usa un espacio de direcciones propio.El control se devuelve al padre, ya que su espacio de direcciones ya no está en uso por otro proceso.
Importante: en Linux, no hay una
vfork()
implementación real . Linux implementa más bienvfork()
basado en elfork()
concepto Copy on Write introducido por SunOS-4.0 en 1988. Para hacer que los usuarios crean que usanvfork()
, Linux simplemente configura datos compartidos y suspende al padre mientras el niño no llamó_exit()
o una de lasexec*()
funciones.Por lo tanto, Linux no se beneficia del hecho de que un real
vfork()
no necesita configurar una descripción de espacio de direcciones para el niño en el núcleo. Esto resulta en unvfork()
que no es más rápido quefork()
. En los sistemas que implementan un realvfork()
, generalmente es 3 veces más rápidofork()
y afecta el rendimiento de los shells que usanvfork()
-ksh93
, el recienteBourne Shell
ycsh
.La razón por la que nunca debe llamar
exit()
desde el elementovfork()
secundario ed es queexit()
elimina stdio en caso de que haya datos no reflejados del momento anterior a la llamadavfork()
. Esto podría causar resultados extraños.Por cierto:
posix_spawn()
se implementa ademásvfork()
, porvfork()
lo que no se eliminará del sistema operativo. Se ha mencionado que Linux no usavfork()
paraposix_spawn()
.Para la pila, hay poca documentación, esto es lo que dice la página de manual de Solaris:
Entonces la implementación puede hacer lo que quiera. La implementación de Solaris usa memoria compartida para el marco de la pila de la función que llama
vfork()
. Ninguna implementación otorga acceso a las partes más antiguas de la pila desde el padre.fuente
posix_spawn()
sobre Linuxvfork()
. Ambos lo implementan encima__clone()
.vfork()
solo llama,clone()
¿verdad? Es literalmente una línea en el núcleo.vfork
yfork
en Linux, está haciendo algo mal.