fork()
fue la llamada del sistema UNIX original. Solo se puede usar para crear nuevos procesos, no subprocesos. Además, es portátil.
En Linux, clone()
es una llamada al sistema nueva y versátil que se puede utilizar para crear un nuevo hilo de ejecución. Dependiendo de las opciones pasadas, el nuevo subproceso de ejecución puede adherirse a la semántica de un proceso UNIX, un subproceso 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 archivos, varios espacios de nombres, controladores de señales, etc., se comparten o copian.
Desde clone()
es la llamada al sistema superconjunto, la implementación del fork()
el envoltorio de llamada del sistema en glibc en realidad llama a clone()
, pero este es un detalle de implementación que los programadores no necesitan conocer. El verdadero fork()
real La llamada al sistema todavía existe en el kernel de Linux por razones de compatibilidad con versiones anteriores, aunque 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 utiliza para implementar el pthread_create()
Función POSIX para crear hilos.
Los programas portátiles deben llamar a fork()
y pthread_create()
, no clone()
.
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 al hacer man 2 clone
.
Si lee esa página del manual lo suficientemente cerca, verá 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 con un nombre idéntico y confuso.
Escribí un programa corto:
#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;
}
Compilado con:c99 -Wall -Wextra
y lo ejecutó bajo strace -f
para ver qué hacen realmente las llamadas al sistema. Saqué esto de strace
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 ninguna llamada de "bifurcación" en el strace
producción. El clone()
llamada que aparece en el strace
la salida tiene argumentos muy diferentes de la página del manual-clon. child_stack=0
ya que el primer argumento es diferente a int (*fn)(void *)
.
Parece que el fork(2)
la llamada al sistema se implementa en términos de real clone()
, al igual que la "función de biblioteca" clone()
está implementado. El real clone()
tiene un conjunto diferente de argumentos del clon de la página del manual.
Simplistamente, sus declaraciones aparentemente contradictorias sobre fork()
y clone()
son correctos Sin embargo, el "clon" involucrado es diferente.
fork()
es solo un conjunto particular de banderas para la llamada al sistema clone()
. clone()
es lo suficientemente general como para crear un "proceso" o un "subproceso" o incluso cosas extrañas que se encuentran en algún lugar entre procesos y subprocesos (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 kernel, clone()
le da la opción de crear un alias para esa información o copiarla. Los subprocesos corresponden al aliasing, los procesos corresponden a la copia. Especificando combinaciones intermedias de banderas para clone()
, puedes crear cosas extrañas que no son subprocesos o procesos. Por lo general, no debería hacer esto, e imagino que hubo cierto debate durante el desarrollo del kernel de Linux sobre si debería permitir un mecanismo tan general como clone()
.