Fork vs Clone su Linux 2.6 Kernel


37

Ho un po 'di confusione per quanto riguarda fork e clone. Ho visto che:

  • fork è per processi e clone per thread

  • fork chiama solo clone, il clone viene utilizzato per tutti i processi e thread

Uno di questi è accurato? Qual è la distinzione tra queste 2 syscalls con un kernel Linux 2.6?

Risposte:


52

fork()era la chiamata di sistema UNIX originale. Può essere utilizzato solo per creare nuovi processi, non thread. Inoltre, è portatile.

In Linux, clone()è una nuova chiamata di sistema versatile che può essere utilizzata per creare un nuovo thread di esecuzione. A seconda delle opzioni passate, il nuovo thread di esecuzione può aderire alla semantica di un processo UNIX, un thread POSIX, una via di mezzo o qualcosa di completamente diverso (come un contenitore diverso). È possibile specificare tutti i tipi di opzioni che determinano se la memoria, i descrittori di file, i vari spazi dei nomi, i gestori dei segnali e così via vengano condivisi o copiati.

Poiché clone()è la chiamata di sistema superset, l'implementazione del fork()wrapper di chiamata di sistema in glibc in realtà chiama clone(), ma questo è un dettaglio di implementazione che i programmatori non devono conoscere. La vera fork()chiamata di sistema reale esiste ancora nel kernel Linux per motivi di compatibilità con le versioni precedenti anche se è diventata ridondante, perché potrebbero essere utilizzati da programmi che usano versioni molto vecchie di libc o un'altra libc oltre a glibc.

clone()viene anche utilizzato per implementare la pthread_create()funzione POSIX per la creazione di thread.

I programmi portatili dovrebbero chiamare fork()e pthread_create(), no clone().


2
posix_spawn è un'altra funzione rilevante, sia in qualche modo più che meno portatile di fork.
Casuale 832

10

Sembra che ci siano due clone()cose fluttuanti in Linux 2.6

C'è una chiamata di sistema:

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

Questo è il "clone ()" descritto facendo man 2 clone.

Se leggi quella pagina man abbastanza vicino, vedrai questo:

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

Apparentemente, dovresti implementare il threading usando la "funzione di libreria" stratificata sulla chiamata di sistema confusamente identica.

Ho scritto un breve programma:

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

Compilato con:, c99 -Wall -Wextraed eseguito sotto strace -fper vedere cosa fanno effettivamente le chiamate di sistema. Ho ottenuto questo da straceuna macchina 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)

Nessuna chiamata "fork" appare stracenell'output. La clone()chiamata che appare stracenell'output ha argomenti molto diversi dal clone di man-page. child_stack=0poiché il primo argomento è diverso da int (*fn)(void *).

Sembra che la fork(2)chiamata di sistema sia implementata in termini reali clone() , proprio come la "funzione di libreria" clone()è implementata. Il reale clone() ha una serie di argomenti diversa dal clone di man-page.

Semplicisticamente, entrambe le tue dichiarazioni apparentemente contraddittorie su fork()e clone()sono corrette. Il "clone" coinvolto è però diverso.


9
"In realtà è una funzione di libreria sovrapposta alla chiamata di sistema clone () sottostante." - in generale, questo vale per ogni chiamata di sistema. I programmatori in realtà praticamente chiamano sempre funzioni in libc che prendono il nome dalla chiamata di sistema. Questo perché effettuare una vera chiamata di sistema reale direttamente da C richiede una magia specifica della piattaforma (di solito forzando una trappola della CPU di qualche tipo, dipende dall'architettura ABI) e il codice macchina meglio lasciato delegato a libc.
Celada,

1
@Celada - sì, d'accordo. È solo che le man 2 clonefrasi esattamente in quel modo, che pensavo stesse confondendo il problema e impedendo all'interrogante di ottenere una buona risposta.
Bruce Ediger,

2
Credo che la manpage significhi che l' elenco degli argomenti della clonefunzione di libreria differisce sostanzialmente dall'elenco degli argomenti accettato dalla chiamata di sistema sottostante. In particolare, la chiamata di sistema ritorna sempre due volte sullo stesso stack, come forkfa la tradizionale ; tutti gli argomenti relativi allo stack figlio sono gestiti rigorosamente nello spazio utente. Vedere ad esempio sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/…
zwol

1
Volevo dare alla tua risposta la migliore risposta perché oscilla, ma sono stato influenzato dal branco e ho scelto la prima risposta. Riceve punti per i tempi di risposta. Grazie per la tua spiegazione.
Gregg Leventhal,

6

fork()è solo un particolare set di flag per la chiamata di sistema clone(). clone()è abbastanza generale per creare un "processo" o un "thread" o anche cose strane che si trovano a metà strada tra processi e thread (ad esempio, diversi "processi" che condividono la stessa tabella descrittore di file).

In sostanza, per ogni "tipo" di informazioni associate a un contesto di esecuzione nel kernel, clone()è possibile scegliere di aliasare tali informazioni o copiarle. I thread corrispondono all'aliasing, i processi corrispondono alla copia. Specificando combinazioni intermedie di flag per clone(), puoi creare cose strane che non sono thread o processi. Di solito non dovresti farlo, e immagino che durante lo sviluppo del kernel Linux ci sia stato un dibattito sul fatto che dovrebbe consentire un meccanismo così generale come clone().

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.