¿Por qué la bifurcación predeterminada del mecanismo de creación de procesos?

46

La llamada al sistema UNIX para la creación de procesos, fork (), crea un proceso hijo copiando el proceso padre. Tengo entendido que esto casi siempre es seguido por una llamada a exec () para reemplazar el espacio de memoria del proceso secundario (incluido el segmento de texto). Copiar el espacio de memoria de los padres en fork () siempre me pareció un desperdicio (aunque me doy cuenta de que el desperdicio se puede minimizar haciendo que los segmentos de memoria se copien y escriban para que solo se copien los punteros). De todos modos, ¿alguien sabe por qué se requiere este enfoque de duplicación para la creación de procesos?

Ellen Spertus
fuente
3
Tenga en cuenta que la fork(2)página de manual de Linux dice: Under Linux, fork() is implemented using copy-on-write pages, so the only penalty that it incurs is the time and memory required to duplicate the parent's page tables, and to create a unique task structure for the child. Me imagino (pero no lo sé con certeza) que este es el caso de otros sabores modernos de Unix.
larsks
44
El original, PDP-11 Unix realmente, realmente copió todos los bytes de un proceso bifurcado: pero solo tenía 64Kb de ejecutable, y como máximo 64Kb de datos, por lo que no fue una gran carga, incluso en 1975. Lo haría Supongo que CADA UNIX y unix-like desde aproximadamente 1990 ha tenido segmentos de texto de copia en escritura, por lo que ni siquiera estoy seguro de por qué los libros y artículos propagan "problema de rendimiento con fork".
Bruce Ediger
Hoy en día, fork se implementa de manera similar a vfork ( openbsd.org/cgi-bin/… ). Es eficiente, no te preocupes.
Aki
También tenga en cuenta que hay muchos usos en los que no se ejecuta después de una bifurcación (o al menos, no se ejecuta de inmediato): piense en tuberías y servidores web.
jfg956
Puedes pensar que sería lento. Pero como dice @cjm, mire la alternativa que Microsoft usa CreateProcess, tuvieron que implementar subprocesos temprano (puede ser lo único que conducen), porque CreateProcess es lento. (También necesitaban hilos porque selectestaba roto, pero esa es otra historia).
ctrl-alt-delor

Respuestas:

57

Es para simplificar la interfaz. La alternativa forky execsería algo así como la función CreateProcess de Windows . Observe cuántos parámetros CreateProcesstiene, y muchos de ellos son estructuras con aún más parámetros. Esto se debe a que debe pasar todo lo que desee controlar sobre el nuevo proceso CreateProcess. De hecho, CreateProcessno tiene suficientes parámetros, por lo que Microsoft tuvo que agregar CreateProcessAsUser y CreateProcessWithLogonW .

Con el fork/execmodelo, no necesita todos esos parámetros. En cambio, ciertos atributos del proceso se conservan en todo exec. Esto le permite fork, luego cambiar los atributos de proceso que desee (usando las mismas funciones que usaría normalmente), y luego exec . En Linux, forkno tiene parámetros, y execvesolo tiene 3: el programa a ejecutar, la línea de comando para darle y su entorno. (Hay otras execfunciones, pero son solo envoltorios execveproporcionados por la biblioteca C para simplificar los casos de uso comunes).

Si desea iniciar un proceso con un directorio actualizado diferente: fork, chdir, exec.

Si desea redirigir stdin / stdout: fork, cerrar / abrir archivos, exec.

Si quieres usuarios del interruptor: fork, setuid, exec.

Todas estas cosas se pueden combinar según sea necesario. Si a alguien se le ocurre un nuevo tipo de atributo de proceso, no tiene que cambiar forky exec.

Como se mencionó anteriormente, la mayoría de los Unix modernos usan copia en escritura, por lo forkque no implica una sobrecarga significativa.

cjm
fuente
16
Excelente explicación "Los que no entienden UNIX están condenados a reinventarlo mal". - Henry Spencer
Kyle Jones
1
¡Gracias! ¿Tienes alguna referencia, por casualidad?
Ellen Spertus
1
@Aki, nope, CreateProcess () literalmente crea un nuevo proceso y lo construye desde cero, sin bifurcación.
psusi
2
¿Pero no debe haber algún equivalente de CreateProcess () en algún lugar de Unix? De lo contrario, ¿cómo se crea el primer proceso? A diferencia de un dios creador mitológico, el primer proceso no puede bifurcarse () de la nada. ;-)
Steven lunes
2
@StevenMonday, sí, pero está en el código de inicialización del núcleo y no es accesible externamente. No necesita todos esos parámetros porque casi todo está codificado. Solo puede crear el ID de proceso 1, también conocido como proceso de inicio. Después de eso, los procesos se crean solo por bifurcación.
cjm
5

Además de la respuesta de cjm, la especificación Single Unix define una función llamada vfork(). Esa función funciona como una bifurcación, excepto que el proceso bifurcado tiene un comportamiento indefinido si hace algo más que intentar llamar a una función familiar ejecutiva o llamar _exit().

Por lo tanto, prácticamente el único uso con comportamiento definido es:

pid_t ret = vfork();
if(ret == 0)
{
    exec(...);
    _exit(EXIT_FAILURE); //in case exec failed for any reason.
}

Entonces, ¿qué hace vfork? Es de bajo costo fork. En implementaciones sin copia en escritura, el proceso resultante compartirá espacio de memoria con el proceso original (de ahí el comportamiento indefinido). En implementaciones con copia en escritura, vforkse permite que sea idéntico fork(), ya que las implementaciones de copia en escritura son rápidas.

También existe la posix_spawnfunción opcional (y una posix_spawnpfunción) que puede crear directamente un nuevo proceso. (También está permitido implementarlos con una llamada a la biblioteca usando forky exec, y se proporciona un ejemplo de implementación).

Kevin Cathcart
fuente