Fork vs Clone en 2.6 Kernel Linux

37

Tengo cierta confusión con respecto a tenedor y clon. He visto eso:

  • fork es para procesos y clon para hilos

  • fork simplemente llama clone, clone se usa para todos los procesos y subprocesos

¿Alguno de estos es exacto? ¿Cuál es la distinción entre estas 2 llamadas al sistema con un núcleo Linux 2.6?

Gregg Leventhal
fuente

Respuestas:

52

fork()fue la llamada original al sistema UNIX. Solo se puede usar para crear nuevos procesos, no hilos. Además, es portátil.

En Linux, clone()es una nueva y versátil llamada al sistema que se puede usar para crear un nuevo hilo de ejecución. Dependiendo de las opciones pasadas, el nuevo hilo de ejecución puede adherirse a la semántica de un proceso UNIX, un hilo POSIX, algo intermedio o algo completamente diferente (como un contenedor diferente). Puede especificar todo tipo de opciones que dictan si la memoria, los descriptores de archivo, los diversos espacios de nombres, los controladores de señales, etc., se comparten o copian.

Dado que clone()es la llamada al sistema de superconjunto, la implementación del fork()envoltorio de llamada del sistema en glibc realmente llama clone(), pero este es un detalle de implementación que los programadores no necesitan conocer. La fork()llamada real al sistema real todavía existe en el kernel de Linux por razones de compatibilidad con versiones anteriores a pesar de que se ha vuelto redundante, porque los programas que usan versiones muy antiguas de libc, u otra libc además de glibc, podrían usarla.

clone()también se usa para implementar la pthread_create()función POSIX para crear hilos.

Los programas portátiles deben llamar fork()y pthread_create()no clone().

Celada
fuente
2
posix_spawn es otra función relevante, tanto más y menos portátil que fork de alguna manera.
Random832
10

Parece que hay dos clone()cosas flotando en Linux 2.6

Hay una llamada al sistema:

int clone(int (*fn)(void *), void *child_stack,
          int flags, void *arg, ...
          /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );

Este es el "clon ()" descrito haciendo man 2 clone.

Si lees esa página de manual lo suficientemente cerca, verás esto:

It is actually a library function layered on top of the
underlying clone() system call.

Aparentemente, se supone que debe implementar subprocesos utilizando la "función de biblioteca" en capas en la llamada al sistema confusamente identificada.

Escribí un breve programa:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int
main(int ac, char **av)
{
    pid_t cpid;
    switch (cpid = fork()) {
    case 0:   // Child process
        break;
    case -1:  // Error
        break;
    default:  // parent process
        break;
    }
    return 0;
}

Lo compilé con: c99 -Wall -Wextray lo ejecuté strace -fpara ver qué hace realmente la bifurcación de llamadas del sistema. straceObtuve esto en una máquina Linux 2.6.18 (CPU x86_64):

20097 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x2b4ee9213770) = 20098
20097 exit_group(0)                     = ?
20098 exit_group(0)

No aparece la llamada "fork" en la stracesalida. La clone()llamada que aparece en la stracesalida tiene argumentos muy diferentes del clon de página de manual. child_stack=0como primer argumento es diferente int (*fn)(void *).

Parece que la fork(2)llamada al sistema se implementa en términos reales clone() , al igual que clone()se implementa la "función de biblioteca" . Lo real clone() tiene un conjunto diferente de argumentos del clon de la página de manual.

Simplísticamente, sus dos declaraciones aparentemente contradictorias sobre fork()y clone()son correctas. Sin embargo, el "clon" involucrado es diferente.

Bruce Ediger
fuente
99
"En realidad es una función de biblioteca en capas sobre la llamada al sistema clone () subyacente". - en general, esto se aplica a todas las llamadas al sistema. Los programadores prácticamente siempre invocan funciones en libc que llevan el nombre de la llamada al sistema. Esto se debe a que realizar una llamada real al sistema real directamente desde C requiere magia específica de la plataforma (generalmente forzando una trampa de CPU de algún tipo, depende de la arquitectura ABI) y el código de la máquina es mejor delegarlo en libc.
Celada
1
@Celada: sí, de acuerdo. Es solo que las man 2 clonefrases son exactamente de esa manera, lo que pensé que confundía el tema y evitaba que el interlocutor obtuviera una buena respuesta.
Bruce Ediger
2
Creo que la página de manual significa indicar que la lista de argumentos de la clonefunción de biblioteca difiere sustancialmente de la lista de argumentos aceptada por la llamada al sistema subyacente. Específicamente, la llamada al sistema siempre regresa dos veces en la misma pila, de la manera tradicional fork; Todos los argumentos relacionados con la pila secundaria se manejan estrictamente en el espacio del usuario. Ver por ejemplo sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/…
zwol
1
Quería darle la mejor respuesta a tu respuesta porque es genial, pero la manada me dejó influir y fui con la primera respuesta. Ella obtiene puntos por el tiempo de respuesta. Gracias por tu explicación.
Gregg Leventhal
6

fork()es solo un conjunto particular de indicadores para la llamada al sistema clone(). clone()es lo suficientemente general como para crear un "proceso" o un "hilo" o incluso cosas extrañas que se encuentran en algún punto entre los procesos y los hilos (por ejemplo, diferentes "procesos" que comparten la misma tabla de descriptores de archivos).

Esencialmente, para cada "tipo" de información asociada con un contexto de ejecución en el núcleo, clone()le da la opción de alias esa información o copiarla. Los hilos corresponden al alias, los procesos corresponden a la copia. Al especificar combinaciones intermedias de indicadores para clone(), puede crear cosas extrañas que no son hilos o procesos. Por lo general, no debería hacer esto, e imagino que hubo un debate durante el desarrollo del kernel de Linux sobre si debería permitir un mecanismo tan general como clone().

Atsby
fuente