2010-11-23 6 views

Respuesta

30

La intención de vfork fue eliminar la sobrecarga de la copia de la imagen de proceso entera si sólo desea hacer una exec* en el niño. Como exec* reemplaza la imagen completa del proceso secundario, no tiene sentido copiar la imagen del elemento primario.

if ((pid = vfork()) == 0) { 
    execl(..., NULL); /* after a successful execl the parent should be resumed */ 
    _exit(127); /* terminate the child in case execl fails */ 
} 

Para otros tipos de usos, vfork es peligroso e impredecible.

Sin embargo, con la mayoría de los kernels actuales, incluido Linux, el beneficio principal de vfork ha desaparecido debido a la forma en que se implementa fork. En lugar de copiar toda la imagen cuando se ejecuta fork, se utilizan técnicas de copiado por escritura.

+1

Los sistemas basados ​​en BSD todavía tienen una función real * vfork *. Lee la fuente. – tchrist

+6

Linux también tiene un 'vfork real (2)'. En general, supongo que cada * nix que ha sido portado a plataformas que no son MMU tiene un 'vfork real (2)' real. – ninjalj

+2

Importante para tener en cuenta * técnicas de copiado sobre escritura *. La memoria se copia solo si el nuevo proceso intenta modificarla. muy crítico para sistemas como Android. –

4

Desde mi página de manual

(De POSIX.1) La función vfork() tiene el mismo efecto que el tenedor (2), excepto que el comportamiento no está definido si el proceso creado por vfork() modifica cualquier información que no sea una variable de tipo pid_t usada para almacenar el valor de retorno de vfork(), o devuelve de la función en la que se llamó vfork() o llama a cualquier otra función antes de llamar con éxito _exit (2) o uno de los exec (3) fam il de funciones.

vfork() difiere de tenedor (2) en que el padre se suspende hasta que el niño termina (ya sea normalmente, por llamando _exit (2), o anormalmente, después de la entrega de una señal fatal), o hace una llamada a execve (2). Hasta ese momento, el hijo comparte toda la memoria con su padre, incluida la pila. El niño no debe devolver desde el la función actual o llamar a exit (3), , pero puede llamar a _exit (2).

+0

+1 páginas RTF man. Además, el enlace xkcd desde que xkcd tiene un cómic para * cada * ASUNCIÓN: http://xkcd.org/293 – delnan

+2

También vale la pena señalar que 'vfork()' es principalmente un artefacto histórico: en los sistemas modernos con copia sana -write semántica, 'vfork()' generalmente no gana mucho (si es que algo, a veces es esencialmente un alias para 'fork()'!). –

0

Consulte here y desde wikipedia -

En algunos sistemas, vfork() es el mismo como tenedor(). La función vfork() difiere de fork() solo en que el proceso hijo puede compartir el código y los datos con el proceso de llamada (proceso principal ).

18

Como ya se indicó, la página de manual de vfork es clara sobre las diferencias. Este topic da una buena descripción de fork, vfork, clone y exec.

A continuación se presentan algunas diferencias que a menudo se pasan por alto entre fork y vfork que experimenté en algunos sistemas embebidos Linux 2.6.3x con los que trabajé.

Incluso con las técnicas de copiado en escritura, fork falla si no tiene suficiente memoria para duplicar la memoria utilizada por el proceso principal. Por ejemplo, si el proceso principal usa 2 GB de memoria residente (es decir, memoria que se usa y no solo asignada), fork falla si tiene menos de 2 GB de memoria libre. Eso es frustrante cuando solo quieres exec un programa simple y por lo tanto nunca necesitarás ese enorme espacio de direcciones para padres.

vfork no tiene este problema de memoria, ya que no duplica el espacio de direcciones principal. El proceso hijo actúa más como un hilo en el que puede llamar al exec* o _exit sin dañar el proceso principal.

Debido a las tablas de páginas de memoria no se duplican, vfork es mucho más rápido que fork y tiempo de ejecución vfork 's no se ve afectada por la cantidad de memoria utilizada por el proceso padre, como se ha señalado aquí: http://blog.famzah.net/2009/11/20/fork-gets-slower-as-parent-process-use-more-memory/

en situaciones en las el rendimiento es crítico y/o la memoria limitada, vfork + exec* puede por lo tanto ser una buena alternativa a fork + exec*. El problema es que es menos seguro y la página de manual dice vfork es probable que quede obsoleto en el futuro.

Una solución más segura y portátil puede ser observar la función posix_spawn, que es de mayor nivel y ofrece más opciones. Usa de manera segura vfork cuando sea posible, dependiendo de las opciones que pase. He podido usar posix_spawn con éxito y superar ese molesto "problema de doble verificación de memoria" que fork + exec me estaba dando.

A really good page on this topic, with links to some posix_spawn examples.

+2

Incidentalmente, 'Runtime.exec()' de Java ha utilizado tradicionalmente 'fork()/exec()', pero IIRC Java 1.7 usará 'vfork()/exec()' o 'posix_spawn()' donde esté disponible. – ninjalj

2

Algunos sistemas tienen un vfork llamada al sistema(), que fue diseñado originalmente como una versión de menor sobrecarga de tenedor(). Como fork() implicó copiar todo el espacio de direcciones del proceso, y, por lo tanto, era bastante caro, se introdujo la función vfork() (en 3.0BSD).

Sin embargo, desde que se introdujo vfork(), la implementación de fork() ha mejorado drásticamente, sobre todo con la introducción de `copy-on-write ', donde la copia del espacio de direcciones de proceso se falsifica ambos procesos hacen referencia a la misma memoria física hasta que cualquiera de ellos la modifique. Esto elimina en gran medida la justificación de vfork(); de hecho, una gran proporción de sistemas ahora carecen completamente de la funcionalidad original de vfork(). Sin embargo, para compatibilidad, todavía puede haber una llamada vfork() presente, que simplemente llama a fork() sin intentar emular toda la semántica de vfork().

Como resultado, es muy imprudente utilizar realmente cualquiera de las diferencias entre fork() y vfork(). De hecho, probablemente no sea prudente usar vfork() en absoluto, a menos que sepa exactamente por qué lo desea.

La diferencia básica entre los dos es que cuando se crea un nuevo proceso con vfork(), el proceso principal se suspende temporalmente, y el proceso secundario puede tomar prestado el espacio de direcciones del padre. Este extraño estado de cosas continúa hasta que el proceso secundario se cierra o se llama a execve(), en cuyo punto continúa el proceso principal.

Esto significa que el proceso hijo de vfork() debe tener cuidado para evitar la modificación inesperada de las variables del proceso principal.En particular, el proceso hijo no debe regresar de la función que contiene la llamada vfork(), y no debe llamar a exit() (si necesita salir, debe usar _exit(); en realidad, esto también es cierto para el niño de una horquilla normal()).

0

La diferencia básica entre los dos es que cuando se crea un nuevo proceso con vfork(), el proceso padre se suspende temporalmente, y el proceso secundario puede tomar prestado el espacio de direcciones del padre. Este extraño estado de cosas continúa hasta que el proceso secundario se cierra o llama al execve(), momento en el que continúa el proceso principal.

Esto significa que el proceso secundario de vfork() debe tener cuidado al evitar la modificación inesperada de las variables del proceso principal. En particular, el proceso hijo no debe regresar a la función que contiene la llamada vfork(), y no debe llamar exit() (si tiene que salir, se debe utilizar _exit(); realidad, esto también es cierto para el niño de un normales fork()).

Sin embargo, desde vfork() se introdujo, el implementación de fork() ha mejorado drásticamente, sobre todo con la introducción de 'copia en escritura', , donde la copia del espacio de direcciones proceso es transparente falsificada al permitir ambos procesos para referirse a la misma memoria física hasta que cualquiera de ellos modifique . Esto elimina en gran parte la justificación de vfork(); de hecho, una gran proporción de sistemas ahora carecen completamente de la funcionalidad original de vfork(). Por compatibilidad, sin embargo, todavía puede haber una llamada vfork() presente, que simplemente llama a fork() sin intentando emular toda la semántica vfork().

Como resultado, es muy imprudente utilizar realmente cualquiera de las diferencias entre fork() y vfork(). De hecho, es probablemente imprudente usar vfork() en absoluto, a menos que sepa exactamente por qué desea hacerlo.

Cuestiones relacionadas