stringtranslate.com

bifurcación (llamada al sistema)

En informática , particularmente en el contexto del sistema operativo Unix y sus similares , fork 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 Especificación única de UNIX . Por lo general, se implementa como un contenedor de biblioteca estándar de C 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 tipo Unix.

Descripció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 tipo 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 del sistema exec para superponerse al otro programa: cesa la ejecución de 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 hacer referencia a las mismas páginas de memoria física hasta que una de ellas escribe en dicha página: luego se copia. Esta optimización es importante en el caso común en el que se utiliza fork junto con exec para ejecutar un nuevo programa: normalmente, el proceso hijo realiza sólo un pequeño conjunto de acciones antes de detener la ejecución de su programa en favor del programa que se va a iniciar. y requiere muy pocas, o ninguna, de las estructuras de datos de su padre .

Cuando un proceso llama a una 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 sólo 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 al concepto de bifurcación apareció en A Multiprocessor System Design de Melvin Conway , publicado en 1962. [1] El artículo de Conway motivó la implementación por parte de L. Peter Deutsch de la bifurcación en el sistema de tiempo compartido GENIE , donde el concepto era tomado prestado por Ken Thompson para su primera aparición [2] en Research Unix . [3] [4] Posteriormente, Fork se convirtió en una interfaz estándar en POSIX . [5]

Comunicación

El proceso hijo comienza con una copia de los descriptores de archivos 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á los extremos de las tuberías que no necesitan. [6]

Variantes

Vfork

Vfork es una variante de fork con la misma convención de llamadas y prácticamente 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 que admitía 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 principal se suspenderá hasta que el proceso secundario haya completado la ejecución o haya sido reemplazado con una nueva imagen ejecutable a través de una de la familia de llamadas al sistema " exec ". El niño toma prestada la configuración de la unidad de administración de memoria del padre y las páginas de memoria se comparten entre el proceso padre y el hijo sin realizar copias 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 simple bifurcación en entornos de copia completa cuando se usa con exec. En POSIX, el uso de vfork para cualquier propósito excepto como preludio a una llamada inmediata a una función de la familia exec (y algunas otras operaciones selectas) 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 utiliza la semántica de copia sobre escritura.

System V no admitía esta llamada de función antes de que se introdujera System VR4, [ cita necesaria ] porque el intercambio 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 System V. Pero el proceso hijo se ejecuta en el mismo espacio de direcciones físicas que el proceso padre (hasta un exec o exit ) 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 núcleo ocultar a los usuarios las idiosincrasias de su implementación, o debería permitir a los usuarios sofisticados la oportunidad de aprovechar la implementación para realizar 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 su uso: [7] [ verificación fallida ] [ discutir ]

Es bastante desafortunado que Linux haya revivido este espectro del pasado. La página de manual de BSD indica: "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 multiproceso 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 fork , 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ñados 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 4.4BSD eliminó la implementación de vfork, lo que provocó que vfork tuviera el mismo comportamiento que fork, luego se restableció en el sistema operativo NetBSD por razones de rendimiento. [8]

Algunos sistemas operativos integrados, como uClinux, omiten 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 unidad de administración de memoria.

rfork

El sistema operativo Plan 9 , creado por los diseñadores de Unix, incluye un fork pero también una variante llamada "rfork" que permite compartir recursos detalladamente entre procesos padre e hijo, incluido el espacio de direcciones (excepto un segmento de pila , que es único para cada proceso), variables de entorno y el espacio de nombres del sistema de archivos; [15] esto lo convierte en una interfaz unificada para la creación tanto de procesos como de subprocesos dentro de ellos. [16] Tanto FreeBSD [17] como IRIX adoptaron la llamada al sistema rfork del Plan 9, y este último le cambió el nombre a "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 puede usarse para implementar subprocesos (aunque los programadores de aplicaciones normalmente usarán una interfaz de nivel superior como pthreads , implementada sobre el clon). La característica de "pilas separadas" del Plan 9 e IRIX se ha omitido porque (según Linus Torvalds ) causa demasiada sobrecarga. [18]

Bifurcación en otros sistemas operativos

En el diseño original del sistema operativo VMS (1977), se consideraba arriesgada una operación de copia con la posterior mutación del contenido de unas pocas direcciones específicas para el nuevo proceso, como en el caso de una bifurcación. [ cita necesaria ] Los errores en el estado del proceso actual se pueden copiar a un proceso secundario. Aquí se utiliza la metáfora del proceso de generación: cada componente del diseño de la memoria del nuevo proceso se construye desde cero. La metáfora de generación fue adoptada posteriormente en los sistemas operativos de Microsoft (1993).

El componente de compatibilidad POSIX de VM/CMS (OpenExtensions) proporciona una implementación muy limitada de fork, 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 . (Esto se aplica únicamente al sistema operativo invitado CMS; otros sistemas operativos invitados de VM, como Linux, proporcionan una funcionalidad de bifurcación estándar).

Uso de la aplicación

La siguiente variante del mensaje "¡Hola, mundo!" El programa 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 realiza en función del valor de retorno de la llamada al sistema de bifurcación. Se ha omitido el código repetitivo , como las inclusiones de encabezados .

int principal ( vacío ) { pid_t pid = bifurcación ();      if ( pid == -1 ) { perror ( "falló la bifurcación" ); salir ( EXIT_FAILURE ); } else if ( pid == 0 ) { printf ( "¡Hola desde el proceso hijo! \n " ); _salir ( SALIDA_SUCCESS ); } más { int estado ; ( nulo ) waitpid ( pid , & estado , 0 ); } devolver EXIT_SUCCESS ; }                          

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

 pid_t pid = bifurcación ();   

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

 if ( pid == -1 ) { perror ( "falló la bifurcación" ); 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 fork tuvo éxito, entonces ahora hay dos procesos, ambos ejecutando la función principal desde el punto donde fork regresó. Para que los procesos realicen diferentes tareas, el programa debe bifurcarse en el valor de retorno de fork para determinar si se está ejecutando como proceso hijo o como proceso padre .

 else if ( pid == 0 ) { printf ( "¡Hola desde el proceso hijo! \n " ); _salir ( SALIDA_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, aquí se debe utilizar la función POSIX _exit en lugar de la función de salida estándar C ).

 más { int estado ; ( nulo ) waitpid ( pid , & estado , 0 ); }       

El otro proceso, el padre, recibe del fork 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 sucede, el padre reanuda la ejecución y sale mediante la declaración de devolución .

Ver también

Referencias

  1. ^ Nyman, Linus (25 de agosto de 2016). "Notas sobre la historia de Fork and Join". Anales IEEE de la historia de la informática . 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). "HORQUILLA SYS (II)" (PDF) . Manual del programador de UNIX . Laboratorios Bell .
  4. ^ Ritchie, Dennis M .; Thompson, Ken (julio de 1978). "El sistema de tiempo compartido UNIX" (PDF) . Tecnología del sistema de campana. J.57 (6). AT&T: 1905-1929. doi : 10.1002/j.1538-7305.1978.tb02136.x . Consultado el 22 de abril de 2014 .
  5. ^ ab fork - Referencia de interfaces del sistema, especificación única de UNIX , versión 4 de The Open Group
  6. ^ pipe  - Referencia de interfaces del sistema, especificación única de UNIX , versión 4 de The Open Group
  7. ^ ab vfork(2) -  Manual del programador de Linux - Llamadas al sistema
  8. ^ ab "Documentación de NetBSD: Por qué implementar el vfork () tradicional". Proyecto NetBSD . Consultado el 16 de octubre de 2013 .
  9. ^ "vfork(2)". Manual del programador de UNIX, versión virtual VAX-11 . Universidad de California, Berkeley. Diciembre de 1979.
  10. ^ abc vfork - Referencia de interfaces del sistema, la especificación única de UNIX , versión 3 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. ^ abc Nakhimovsky, Greg (mayo de 2006). "Minimizar el uso de memoria para crear subprocesos de aplicaciones". Red de tecnología Oracle . Corporación Oráculo . Archivado desde el original el 22 de septiembre de 2019.
  13. ^ La implementación de OpenSolaris posix_spawn()
  14. ^ posix_spawn  - Referencia de interfaces del sistema, especificación única de UNIX , versión 4 de The Open Group
  15. ^ fork(2)  -  Manual del programador del Plan 9 , volumen 1
  16. ^ intro(2)  -  Manual del programador del Plan 9 , volumen 1
  17. ^ rfork(2)  -  Manual de llamadas al sistema FreeBSD
  18. ^ ab Torvalds, Linus (1999). "La ventaja de Linux" . Fuentes abiertas: voces de la revolución del código abierto . 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 .