En Unix cada vez que queremos crear un nuevo proceso, bifurcamos el proceso actual, creando un nuevo proceso hijo que es exactamente el mismo que el proceso padre; luego hacemos una llamada al sistema ejecutivo para reemplazar todos los datos del proceso padre con los del proceso nuevo.
¿Por qué creamos una copia del proceso padre en primer lugar y no creamos un nuevo proceso directamente?
process
architecture
fork
sarthak
fuente
fuente
Respuestas:
La respuesta corta es,
fork
está en Unix porque era fácil de adaptar al sistema existente en ese momento, y porque un sistema predecesor en Berkeley había utilizado el concepto de horquillas.De La evolución del sistema de tiempo compartido Unix (se ha resaltado el texto relevante ):
Desde ese documento, Unix ha evolucionado.
fork
seguidoexec
ya no es la única forma de ejecutar un programa.vfork fue creado para ser una bifurcación más eficiente para el caso en el que el nuevo proceso intenta hacer un ejecutivo justo después de la bifurcación. Después de hacer un vfork, los procesos padre e hijo comparten el mismo espacio de datos, y el proceso padre se suspende hasta que el proceso hijo ejecute un programa o salga.
posix_spawn crea un nuevo proceso y ejecuta un archivo en una sola llamada al sistema. Toma un montón de parámetros que le permiten compartir selectivamente los archivos abiertos de la persona que llama y copiar su disposición de señal y otros atributos al nuevo proceso.
fuente
posix_spawn()
hacer los mismos trabajos de reacondicionamiento posteriores a la bifurcación que se pueden hacer fácilmente usando unfork()
código en línea hacen un argumento convincente parafork()
ser mucho más simple de usar.[Repetiré parte de mi respuesta desde aquí .]
¿Por qué no simplemente tener un comando que crea un nuevo proceso desde cero? ¿No es absurdo e ineficiente copiar uno que solo será reemplazado de inmediato?
De hecho, eso probablemente no sería tan eficiente por algunas razones:
La "copia", producido por
fork()
un poco de una abstracción, ya que el núcleo utiliza una copia en escritura del sistema ; todo lo que realmente tiene que crearse es un mapa de memoria virtual. Si la copia llama inmediatamenteexec()
, la mayoría de los datos que se habrían copiado si hubiera sido modificada por la actividad del proceso en realidad nunca tienen que copiarse / crearse porque el proceso no hace nada que requiera su uso.Varios aspectos importantes del proceso secundario (p. Ej., Su entorno) no tienen que duplicarse o establecerse individualmente en función de un análisis complejo del contexto, etc. Simplemente se supone que son los mismos que los del proceso de llamada, y Este es el sistema bastante intuitivo con el que estamos familiarizados.
Para explicar el # 1 un poco más, la memoria que se "copia" pero nunca se accede posteriormente nunca se copia realmente, al menos en la mayoría de los casos. Una excepción en este contexto podría ser si bifurcas un proceso y luego haces que el proceso principal salga antes de que el secundario se reemplace por sí mismo
exec()
. Digo podría porque gran parte del padre podría almacenarse en caché si hay suficiente memoria libre, y no estoy seguro de hasta qué punto esto se explotaría (lo que dependería de la implementación del sistema operativo).Por supuesto, eso no hace que el uso de una copia sea más eficiente que el uso de una pizarra en blanco, excepto que "la pizarra en blanco" no es literalmente nada y debe implicar la asignación. El sistema podría tener una plantilla de proceso genérica en blanco / nueva que copia de la misma manera, 1 pero que en realidad no ahorraría nada frente a la bifurcación de copia en escritura. De modo que el n. ° 1 simplemente demuestra que usar un "nuevo" proceso vacío no sería más eficiente.
El punto n. ° 2 explica por qué el uso de la bifurcación es probablemente más eficiente. El entorno de un niño se hereda de su padre, incluso si es un ejecutable completamente diferente. Por ejemplo, si el proceso principal es un shell y el secundario un navegador web,
$HOME
sigue siendo el mismo para ambos, pero dado que cualquiera de ellos podría cambiarlo posteriormente, deben ser dos copias separadas. El del niño es producido por el originalfork()
.1. Una estrategia que puede no tener mucho sentido literal, pero mi punto es que crear un proceso implica más que copiar su imagen en la memoria del disco.
fuente
fork()
puede hacerlo muy rápidamente (como GL mencionó, del orden de 27 líneas de ensamblaje). Si busca un "crear un proceso desde cero", mirando en la otra dirección,fork()
solo cuesta un poquito más que comenzar desde un proceso creado en blanco (27 líneas de ensamblaje + costo de cierre de identificadores de archivo). Entoncesfork
maneja tanto la bifurcación como la creación correcta, mientrascreate
que solo puede manejar la creación correcta.fork
copiaba toda la memoria del proceso y era muy costoso.Creo que la razón por la que Unix solo tenía la
fork
función de crear nuevos procesos es el resultado de la filosofía de UnixConstruyen una función que hace una cosa bien. Crea un proceso hijo.
Lo que se hace con el nuevo proceso depende del programador. Puede usar una de las
exec*
funciones e iniciar un programa diferente, o no puede usar exec y usar las dos instancias del mismo programa, lo que puede ser útil.Entonces obtienes un mayor grado de libertad ya que puedes usar
y, además, sólo tiene que memorizar los
fork
y lasexec*
llamadas de función, que en la década de 1970 que había que hacer.fuente
Hay dos filosofías de creación de procesos: bifurcación con herencia y creación con argumentos. Unix usa fork, obviamente. (OSE, por ejemplo, y VMS usan el método create). Unix tiene MUCHAS características heredables, y se agregan más periódicamente. ¡Por herencia, estas nuevas características se pueden agregar SIN CAMBIAR LOS PROGRAMAS EXISTENTES! Al usar un modelo de crear con argumentos, agregar nuevas características significaría agregar nuevos argumentos a la llamada a crear. El modelo Unix es más simple.
También ofrece el muy útil modelo fork-exe-exec, donde un proceso puede dividirse en múltiples partes. Esto fue vital cuando no había forma de E / S asíncrona, y es útil cuando se aprovechan múltiples CPU en un sistema. (Preprocesos). Lo he hecho mucho a lo largo de los años, incluso recientemente. En esencia, permite agrupar múltiples 'programas' en un solo programa, por lo que no hay absolutamente ningún espacio para la corrupción o desajustes de versión, etc.
El modelo fork / exec también ofrece la posibilidad de que un niño específico herede un entorno radicalmente extraño, configurado entre el fork y el ejecutivo. Cosas como descriptores de archivos heredados, especialmente. (Una extensión de stdio fd's). El modelo de creación no ofrece la capacidad de heredar nada que no fue imaginado por los creadores de la llamada de creación.
Algunos sistemas también pueden admitir la compilación dinámica de código nativo, donde el proceso está en efecto escribiendo su propio programa de código nativo. En otras palabras, quiere un nuevo programa que se esté escribiendo sobre la marcha, SIN tener que pasar por el ciclo de código fuente / compilador / enlazador y ocupar espacio en disco. (Creo que hay un sistema de lenguaje Verilog que hace esto). El modelo fork lo admite, el modelo create normalmente no lo haría.
fuente
La función fork () no es solo para copiar el proceso padre, devuelve un valor que hace referencia a que el proceso es el proceso padre o hijo, la imagen a continuación explica cómo puede utilizar fork () como padre y hijo:
como se muestra cuando el proceso es el padre fork () devuelve el ID del proceso hijo, de lo
PID
contrario, devuelve0
por ejemplo, puede usarlo si tiene un proceso (servidor web) que recibe las solicitudes y en cada solicitud crea un
son process
para procesar esta solicitud, aquí el padre y sus hijos tienen diferentes trabajos.Por lo tanto, no ejecutar una copia de un proceso no es exactamente lo que fork ().
fuente
fork
si asumes que quieresfork
La redirección de E / S se implementa más fácilmente después de fork y antes de exec. El niño, sabiendo que es el niño, puede cerrar los descriptores de archivo, abrir nuevos, dup () o dup2 () para obtener el número fd correcto, etc., todo sin afectar al padre. Después de hacer eso, y tal vez cualquier cambio de variable de entorno deseado (que tampoco afecte al padre), puede ejecutar el nuevo programa en el entorno personalizado.
fuente
Creo que todos aquí saben cómo funciona fork, pero la pregunta es ¿por qué necesitamos crear un duplicado exacto del padre usando fork? Respuesta ==> Tome un ejemplo de servidor (sin bifurcación), mientras el cliente-1 está accediendo al servidor, si al mismo tiempo llega el segundo cliente-2 y quiere acceder al servidor pero el servidor no da permiso al recién llegado cliente-2 porque el servidor está ocupado para servir al cliente-1 por lo que el cliente-2 tiene que esperar. Después de que todos los servicios al cliente-1 hayan terminado, el cliente-2 ahora puede acceder al servidor. Ahora considere si al mismo tiempo llega el cliente-3, por lo que el cliente-3 tiene que esperar hasta que todos los servicios para el cliente-2 estén terminados. Tome el escenario donde los miles de clientes necesitan acceder al servidor al mismo tiempo ... entonces todos los clientes tienen que espera (el servidor está ocupado !!).
Esto se evita creando (usando una bifurcación) una copia duplicada exacta (es decir, secundaria) del servidor, donde cada elemento secundario (que es una copia duplicada exacta de su padre, es decir, el servidor) se dedica al cliente recién llegado, por lo que simultáneamente todos los clientes acceden al mismo servidor.
fuente
fork
llamada que copia el proceso principal es que no tiene que tener dos programas separados, pero tener programas separados (por ejemplo,inetd
) puede hacer que el sistema sea más modular.