fork (llamada al sistema)


De Wikipedia, la enciclopedia libre
  (Redirigido desde Fork (Unix) )
Saltar a navegación Saltar a búsqueda

En informática , particularmente en el contexto del sistema operativo Unix y sus similares , la bifurcación es una operación mediante la cual un proceso crea una copia de sí mismo. Es una interfaz necesaria para cumplir con los estándares POSIX y Single UNIX Specification . Por lo general, se implementa como un contenedor de la biblioteca estándar de C (libc) para la bifurcación, el clon u otras llamadas al sistema del kernel . Fork es el método principal de creación de procesos en sistemas operativos similares a Unix.

Visión general

En los sistemas operativos multitarea, los procesos (programas en ejecución) necesitan una forma de crear nuevos procesos, por ejemplo, para ejecutar otros programas. Fork y sus variantes suelen ser la única forma de hacerlo en sistemas similares a Unix. Para que un proceso inicie la ejecución de un programa diferente, primero se bifurca para crear una copia de sí mismo. Luego, la copia, llamada " proceso hijo ", llama a la llamada al sistema exec para superponerse con el otro programa: deja de ejecutar su programa anterior en favor del otro.

La operación de bifurcación crea un espacio de direcciones separado para el niño. El proceso hijo tiene una copia exacta de todos los segmentos de memoria del proceso padre. En las variantes modernas de UNIX que siguen el modelo de memoria virtual de SunOS-4.0, se implementa la semántica de copia en escritura y no es necesario copiar la memoria física. En cambio, las páginas de memoria virtual en ambos procesos pueden referirse a las mismas páginas de memoria física.hasta que uno de ellos escribe en dicha página: entonces se copia. Esta optimización es importante en el caso común en el que fork se usa junto con exec para ejecutar un nuevo programa: típicamente, el proceso hijo realiza solo un pequeño conjunto de acciones antes de que cese la ejecución de su programa a favor de que se inicie el programa. y requiere muy pocas, si alguna, de las estructuras de datos de su padre .

Cuando un proceso llama a la bifurcación, se considera el proceso padre y el proceso recién creado es su hijo. Después de la bifurcación, ambos procesos no solo ejecutan el mismo programa, sino que reanudan la ejecución como si ambos hubieran llamado a la llamada al sistema. Luego pueden inspeccionar el valor de retorno de la llamada para determinar su estado, hijo o padre, y actuar en consecuencia.

Historia

Una de las primeras referencias a un concepto de fork apareció en A Multiprocessor System Design by Melvin Conway , publicado en 1962. [1] El artículo de Conway motivó la implementación por L. Peter Deutsch de fork en el sistema de tiempo compartido GENIE , donde el concepto fue tomado prestado por Ken Thompson para su primera aparición [2] en Research Unix . [3] [4] Fork más tarde se convirtió en una interfaz estándar en POSIX . [5]

Comunicación

El proceso hijo comienza con una copia de los descriptores de archivo de su padre . [5] Para la comunicación entre procesos, el proceso padre a menudo creará una o varias tuberías , y luego, después de bifurcar, los procesos cerrarán los extremos de las tuberías que no necesitan. [6]

Variantes

Vfork

Vfork es una variante de la bifurcación con la misma convención de llamadas y la misma semántica, pero solo para usarse en situaciones restringidas. Se originó en la versión 3BSD de Unix, [7] [8] [9] el primer Unix en soportar memoria virtual. Fue estandarizado por POSIX, lo que permitió que vfork tuviera exactamente el mismo comportamiento que fork, pero se marcó como obsoleto en la edición de 2004 [10] y fue reemplazado por posix_spawn () (que normalmente se implementa a través de vfork) en ediciones posteriores.

Cuando se emite una llamada al sistema vfork, el proceso padre se suspenderá hasta que el proceso hijo haya completado la ejecución o haya sido reemplazado por una nueva imagen ejecutable a través de una de las llamadas al sistema de la familia " exec ". El hijo toma prestada la configuración de MMU del padre y las páginas de memoria se comparten entre el proceso padre y el hijo sin realizar ninguna copia y, en particular, sin semántica de copia en escritura ; [10]por lo tanto, si el proceso hijo realiza una modificación en cualquiera de las páginas compartidas, no se creará ninguna página nueva y las páginas modificadas también serán visibles para el proceso padre. Dado que no hay absolutamente ninguna copia de página involucrada (consumiendo memoria adicional), esta técnica es una optimización sobre la bifurcación simple en entornos de copia completa cuando se usa con exec. En POSIX, el uso de vfork para cualquier propósito excepto como preludio de una llamada inmediata a una función de la familia ejecutiva (y algunas otras operaciones seleccionadas) da lugar a un comportamiento indefinido . [10] Al igual que con vfork, el niño toma prestadas estructuras de datos en lugar de copiarlas. vfork es aún más rápido que una bifurcación que usa la semántica de copia en escritura.

System V no admitía esta llamada de función antes de que se introdujera System VR4, [ cita requerida ] porque el uso compartido de memoria que provoca es propenso a errores:

Vfork no copia tablas de páginas, por lo que es más rápido que la implementación de la bifurcación de System V. Pero el proceso hijo se ejecuta en el mismo espacio de direcciones físicas que el proceso padre (hasta que un ejecutivo o sale ) y, por lo tanto, puede sobrescribir los datos y la pila del padre. Podría surgir una situación peligrosa si un programador usa vfork incorrectamente, por lo que la responsabilidad de llamar a vfork recae en el programador. La diferencia entre el enfoque System V y el enfoque BSD es filosófica: ¿Debería el kernel ocultar las idiosincrasias de su implementación a los usuarios, o debería permitir a los usuarios sofisticados la oportunidad de aprovechar la implementación para hacer una función lógica de manera más eficiente?

-  Maurice J. Bach [11]

De manera similar, la página de manual de Linux para vfork desaconseja enfáticamente su uso: [7] [ verificación fallida ] [ discutir ]

Es bastante lamentable que Linux reviviera este espectro del pasado. La página de manual de BSD dice: "Esta llamada al sistema se eliminará cuando se implementen los mecanismos adecuados para compartir el sistema. Los usuarios no deben depender de la semántica de compartir memoria de vfork () ya que, en ese caso, se convertirá en sinónimo de fork (2) . "

Otros problemas con vfork incluyen interbloqueos que pueden ocurrir en programas de subprocesos múltiples debido a interacciones con enlaces dinámicos . [12] Como reemplazo de la interfaz vfork , POSIX introdujo la familia de funciones posix_spawn que combinan las acciones de fork y exec. Estas funciones pueden implementarse como rutinas de biblioteca en términos de bifurcación , como se hace en Linux, [12] o en términos de vfork para un mejor rendimiento, como se hace en Solaris, [12] [13] pero la especificación POSIX señala que fueron "diseñadas como operaciones del kernel", especialmente para sistemas operativos que se ejecutan en hardware restringido y sistemas en tiempo real . [14]

Si bien la implementación de 4.4BSD eliminó la implementación de vfork, lo que provocó que vfork tuviera el mismo comportamiento que fork, luego se reinstaló en el sistema operativo NetBSD por razones de rendimiento. [8]

Algunos sistemas operativos embebidos como uClinux omiten el fork y solo implementan vfork, porque necesitan operar en dispositivos donde la copia en escritura es imposible de implementar debido a la falta de una MMU .

Rfork

El sistema operativo Plan 9 , creado por los diseñadores de Unix, incluye fork, pero también una variante llamada "rfork" que permite el uso compartido detallado de recursos entre procesos padre e hijo, incluido el espacio de direcciones (excepto un segmento de pila , que es único para cada proceso), las variables de entorno y el espacio de nombres del sistema de archivos; [15] esto lo convierte en una interfaz unificada para la creación de procesos y subprocesos dentro de ellos. [16] Tanto FreeBSD [17] como IRIX adoptaron la llamada al sistema rfork del Plan 9, el último renombrándolo como "sproc". [18]

Clon

clonees una llamada al sistema en el kernel de Linux que crea un proceso hijo que puede compartir partes de su contexto de ejecución con el padre. Al igual que el rfork de FreeBSD y el sproc de IRIX, el clon de Linux se inspiró en el rfork de Plan 9 y se puede usar para implementar subprocesos (aunque los programadores de aplicaciones generalmente usarán una interfaz de nivel superior como pthreads , implementada sobre el clon). La función de "pilas separadas" de Plan 9 e IRIX se ha omitido porque (según Linus Torvalds ) provoca demasiada sobrecarga. [18]

Bifurcación en otros sistemas operativos

En el diseño original del sistema operativo VMS (1977), se consideró arriesgada una operación de copia con la posterior mutación del contenido de algunas direcciones específicas para el nuevo proceso como en bifurcación. [ cita requerida ] Los errores en el estado actual del proceso se pueden copiar a un proceso hijo. Aquí, se utiliza la metáfora del proceso de generación: cada componente del diseño de memoria del nuevo proceso se construye desde cero. La metáfora del engendro se adoptó más tarde en los sistemas operativos de Microsoft (1993).

El componente de compatibilidad POSIX de VM / CMS (OpenExtensions) proporciona una implementación muy limitada de bifurcación, en la que el padre se suspende mientras el hijo se ejecuta, y el hijo y el padre comparten el mismo espacio de direcciones. [19] Esto es esencialmente un vfork etiquetado como fork . (Tenga en cuenta que esto se aplica solo al sistema operativo invitado CMS; otros sistemas operativos invitados de VM, como Linux, proporcionan funcionalidad de bifurcación estándar).

Uso de la aplicación

La siguiente variante del programa Hello World demuestra la mecánica de la llamada al sistema fork en el lenguaje de programación C. El programa se bifurca en dos procesos, cada uno de los cuales decide qué funcionalidad realizan en función del valor de retorno de la llamada al sistema de la bifurcación. Se ha omitido el código repetitivo , como las inclusiones de encabezado .

int  main ( vacío ) {  pid_t  pid  =  fork (); if  ( pid  ==  -1 )  {  perror ( "bifurcación fallida" );  salir ( EXIT_FAILURE );  }  else  if  ( pid  ==  0 )  {  printf ( "¡Hola desde el proceso hijo! \ n " );  _exit ( EXIT_SUCCESS );  }  else  {  estado int  ; ( Vacío ) waitpid ( pid , y el estado , 0 );    }  return  EXIT_SUCCESS ; }

Lo que sigue es una disección de este programa.

 pid_t  pid  =  fork ();

La primera instrucción en main llama a la llamada al sistema fork para dividir la ejecución en dos procesos. El valor de retorno de la bifurcación se registra en una variable de tipo pid_t , que es el tipo POSIX para identificadores de proceso (PID).

 if  ( pid  ==  -1 )  {  perror ( "bifurcación fallida" );  salir ( EXIT_FAILURE );  }

Menos uno indica un error en la bifurcación : no se creó ningún proceso nuevo, por lo que se imprime un mensaje de error.

Si la bifurcación tuvo éxito, entonces ahora hay dos procesos, ambos ejecutando la función principal desde el punto donde la bifurcación ha regresado. Para que los procesos realicen diferentes tareas, el programa debe ramificarse en el valor de retorno de la bifurcación para determinar si se está ejecutando como proceso hijo o como proceso padre .

 else  if  ( pid  ==  0 )  {  printf ( "¡Hola desde el proceso hijo! \ n " );  _exit ( EXIT_SUCCESS );  }

En el proceso hijo, el valor de retorno aparece como cero (que es un identificador de proceso no válido). El proceso hijo imprime el mensaje de saludo deseado y luego sale. (Por razones técnicas, la función POSIX _exit debe usarse aquí en lugar de la función de salida estándar de C ).

 else  {  estado int  ; ( Vacío ) waitpid ( pid , y el estado , 0 ); }    

El otro proceso, el padre, recibe de la bifurcación el identificador de proceso del hijo, que siempre es un número positivo. El proceso padre pasa este identificador a la llamada al sistema waitpid para suspender la ejecución hasta que el hijo haya salido. Cuando esto ha sucedido, el padre reanuda la ejecución y sale mediante la declaración de retorno .

Ver también

  • Bomba de horquilla
  • Fork – ejecutivo
  • salir (llamada al sistema)
  • esperar (llamada al sistema)
  • spawn (informática)

Referencias

  1. ^ Nyman, Linus (25 de agosto de 2016). "Notas sobre la historia de Fork y Join". IEEE Annals of the History of Computing . 38 (3): 84–87. doi : 10.1109 / MAHC.2016.34 .
  2. ^ "s3.s de Research UNIX" . GitHub . 1970.
  3. ^ Ken Thompson y Dennis Ritchie (3 de noviembre de 1971). "SYS FORK (II)" (PDF) . Manual del programador de UNIX . Bell Laboratories .
  4. ^ Ritchie, Dennis M .; Thompson, Ken (julio de 1978). "El sistema de tiempo compartido UNIX" (PDF) . Bell System Tech. J . AT&T. 57 (6): 1905-1929. doi : 10.1002 / j.1538-7305.1978.tb02136.x . Consultado el 22 de abril de 2014 .
  5. ^ a b fork  - Referencia de interfaces del sistema, la especificación única de UNIX , número 7 de The Open Group
  6. ^ pipe  - Referencia de interfaces del sistema, la especificación única de UNIX , número 7 de The Open Group
  7. ^ a b vfork(2)  -  Manual del programador de Linux - Llamadas al sistema
  8. ^ a b "Documentación de NetBSD: Por qué implementar vfork () tradicional" . Proyecto NetBSD . Consultado el 16 de octubre de 2013 .
  9. ^ "horquilla (2)". Manual del programador de UNIX, versión Virtual VAX-11 . Universidad de California, Berkeley. Diciembre de 1979.
  10. ^ a b c vfork  - Referencia de interfaces del sistema, la especificación única de UNIX , número 6 de The Open Group
  11. ^ Bach, Maurice J. (1986). El diseño del sistema operativo UNIX . Prentice Hall. págs. 291-292. Bibcode : 1986duos.book ..... B .
  12. ↑ a b c Nakhimovsky, Greg (2006). "Minimizar el uso de memoria para la creación de subprocesos de aplicaciones" . Red de tecnología de Oracle . Oracle Corporation .
  13. ^ La implementación de OpenSolaris posix_spawn (): https://sourceforge.net/p/schillix-on/schillix-on/ci/default/tree/usr/src/lib/libc/port/threads/spawn.c
  14. ^ posix_spawn  - Referencia de interfaces del sistema, la especificación única de UNIX , número 7 de The Open Group
  15. ^ fork(2)  - Manual del programador de Plan 9 , Volumen 1
  16. ^ intro(2)  - Manual del programador de Plan 9 , Volumen 1
  17. ^ rfork(2)  -  Manual de llamadas al sistema FreeBSD
  18. ↑ a b Torvalds, Linus (1999). "El borde de Linux" . Fuentes abiertas: voces de la revolución de las fuentes abiertas . O'Reilly. ISBN 978-1-56592-582-3.
  19. ^ "z / VM> z / VM 6.2.0> Programación de aplicaciones> z / VM V6R2 OpenExtensions Documento de conformidad POSIX> Documento de conformidad POSIX.1> Sección 3. Primitivas de proceso> 3.1 Creación y ejecución de procesos> 3.1.1 Creación de procesos" . IBM . Consultado el 21 de abril de 2015 .
Obtenido de " https://en.wikipedia.org/w/index.php?title=Fork_(system_call)&oldid=1007642694 "