it-swarm.com.de

Fork vs Clone unter 2.6 Kernel Linux

Ich habe einige Verwirrung in Bezug auf Gabel und Klon. Das habe ich gesehen:

  • gabel ist für Prozesse und Klon ist für Threads

  • fork ruft nur clone auf, clone wird für alle Prozesse und Threads verwendet

Sind beide genau? Was ist der Unterschied zwischen diesen beiden Systemaufrufen mit einem 2.6 Linux Kernel?

37
Gregg Leventhal

fork() war der ursprüngliche UNIX-Systemaufruf. Es kann nur zum Erstellen neuer Prozesse verwendet werden, nicht für Threads. Es ist auch tragbar.

Unter Linux ist clone() ein neuer, vielseitiger Systemaufruf, mit dem ein neuer Ausführungsthread erstellt werden kann. Abhängig von den übergebenen Optionen kann der neue Ausführungsthread der Semantik eines UNIX-Prozesses, eines POSIX-Threads, etwas dazwischen oder etwas völlig anderem (wie einem anderen Container) entsprechen. Sie können alle Arten von Optionen angeben, die festlegen, ob Speicher, Dateideskriptoren, verschiedene Namespaces, Signalhandler usw. freigegeben oder kopiert werden sollen.

Da clone() der übergeordnete Systemaufruf ist, ruft die Implementierung des Systemaufruf-Wrappers fork() in glibc tatsächlich clone() auf, aber dies ist ein Implementierungsdetail, das Programmierer nicht verwenden. Ich muss nichts darüber wissen. Der eigentliche echte Systemaufruf fork() ist aus Gründen der Abwärtskompatibilität im Linux-Kernel noch vorhanden, obwohl er redundant geworden ist, da Programme, die sehr alte Versionen von libc oder eine andere libc neben glibc verwenden, ihn möglicherweise verwenden.

clone() wird auch verwendet, um die pthread_create() POSIX-Funktion zum Erstellen von Threads zu implementieren.

Tragbare Programme sollten fork() und pthread_create() aufrufen, nicht clone().

52
Celada

Es scheint, dass in Linux 2.6 zwei clone() Dinge herumschwirren

Es gibt einen Systemaufruf:

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

Dies ist der "clone ()", der mit man 2 clone Beschrieben wird.

Wenn Sie diese Manpage genau genug lesen, sehen Sie Folgendes:

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

Anscheinend sollten Sie das Threading mithilfe der "Bibliotheksfunktion" implementieren, die auf dem verwirrend identischen Systemaufruf liegt.

Ich habe ein kurzes Programm geschrieben:

#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;
}

Kompilierte es mit: c99 -Wall -Wextra Und führte es unter strace -f Aus, um zu sehen, was Systemaufrufe tatsächlich tun. Ich habe dies aus strace auf einem Linux 2.6.18-Computer (x86_64-CPU) erhalten:

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)

In der Ausgabe strace wird kein "Fork" -Aufruf angezeigt. Der Aufruf clone(), der in der Ausgabe strace angezeigt wird, hat ganz andere Argumente als der Manpage-Klon. child_stack=0 Als erstes Argument unterscheidet sich von int (*fn)(void *).

Es scheint, dass der Systemaufruf fork(2) in Bezug auf realclone() implementiert ist, genau wie die "Bibliotheksfunktion" clone() implementiert. Das realclone() hat einen anderen Satz von Argumenten als der Manpage-Klon.

Vereinfacht gesagt sind Ihre beiden scheinbar widersprüchlichen Aussagen zu fork() und clone() richtig. Der "Klon" ist jedoch anders.

10
Bruce Ediger

fork() ist nur ein bestimmter Satz von Flags für den Systemaufruf clone(). clone() ist allgemein genug, um entweder einen "Prozess" oder einen "Thread" oder sogar seltsame Dinge zu erstellen, die sich irgendwo zwischen Prozessen und Threads befinden (z. B. verschiedene "Prozesse", die dieselbe Dateideskriptortabelle verwenden).

Im Wesentlichen gibt clone() für jeden "Typ" von Informationen, die einem Ausführungskontext im Kernel zugeordnet sind, die Wahl, diese Informationen zu aliasen oder zu kopieren. Threads entsprechen Aliasing, Prozesse entsprechen dem Kopieren. Indem Sie Zwischenkombinationen von Flags für clone() angeben, können Sie seltsame Dinge erstellen, die keine Threads oder Prozesse sind. Normalerweise sollten Sie dies nicht tun, und ich kann mir vorstellen, dass während der Entwicklung des Linux-Kernels einige Debatten darüber geführt wurden, ob ein allgemeiner Mechanismus wie clone() zulässig sein sollte.

6
Atsby