Fork vs. Clone no Linux 2.6 do Kernel

32

Eu tenho alguma confusão sobre garfo e clone. Eu vi isso:

  • fork é para processos e clone é para threads

  • fork apenas chama clone, clone é usado para todos os processos e threads

Algum deles é preciso? Qual é a diferença entre esses 2 syscalls com um kernel Linux 2.6?

    
por Gregg Leventhal 30.04.2015 / 20:02

3 respostas

45

fork() foi a chamada original do sistema UNIX. Só pode ser usado para criar novos processos, não threads. Além disso, é portátil.

No Linux, clone() é uma chamada de sistema nova e versátil que pode ser usada para criar um novo thread de execução. Dependendo das opções passadas, o novo thread de execução pode aderir à semântica de um processo UNIX, um thread POSIX, algo intermediário ou algo completamente diferente (como um contêiner diferente). Você pode especificar todos os tipos de opções que determinam se a memória, os descritores de arquivos, os vários namespaces, os manipuladores de sinais e assim por diante serão compartilhados ou copiados.

Como clone() é a chamada de sistema de superconjunto, a implementação do invólucro de chamada de sistema fork() na glibc realmente chama clone() , mas esse é um detalhe de implementação que os programadores não precisam conhecer. A verdadeira chamada de sistema fork() real ainda existe no kernel Linux por razões de retrocompatibilidade, embora tenha se tornado redundante, porque programas que usam versões muito antigas da libc, ou outra libc além da glibc, podem usá-la.

clone() também é usado para implementar a função pthread_create() POSIX para criar encadeamentos.

Os programas portáteis devem chamar fork() e pthread_create() , não clone() .

    
por 30.04.2015 / 20:44
7

Parece que há dois clone() de coisas flutuando no Linux 2.6

Há uma chamada do sistema:

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

Este é o "clone ()" descrito fazendo man 2 clone .

Se você ler essa página man perto o suficiente, verá isso:

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

Aparentemente, você deve implementar o threading usando a "função de biblioteca" em camadas na chamada de sistema de nome identicamente confuso.

Eu escrevi um programa curto:

#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 com: c99 -Wall -Wextra e executado em strace -f para ver o que o sistema chama forking realmente faz. Eu tirei isso de strace em uma máquina Linux 2.6.18 (x86_64 CPU):

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)

Nenhuma chamada "fork" é exibida na saída strace . A chamada clone() que aparece na saída strace tem argumentos muito diferentes do clone man-page. child_stack=0 como o primeiro argumento é diferente de int (*fn)(void *) .

Parece que a chamada do sistema fork(2) é implementada em termos de real clone() , assim como a "função de biblioteca" clone() é implementada. O real clone() tem um conjunto diferente de argumentos do clone man-page.

Simplisticamente, ambas as suas declarações aparentemente contraditórias sobre fork() e clone() estão corretas. O "clone" envolvido é diferente, no entanto.

    
por 30.04.2015 / 20:35
4

fork() é apenas um conjunto específico de sinalizadores para a chamada do sistema clone() . clone() é geral o suficiente para criar um "processo" ou um "encadeamento" ou mesmo coisas estranhas que estão em algum lugar entre processos e encadeamentos (por exemplo, diferentes "processos" que compartilham a mesma tabela de descritores de arquivos).

Essencialmente, para cada "tipo" de informação associado a um contexto de execução no kernel, clone() dá a você a opção de aliasar essas informações ou copiá-las. Os segmentos correspondem ao alias, os processos correspondem à cópia. Especificando combinações intermediárias de sinalizadores para clone() , você pode criar coisas estranhas que não são threads ou processos. Você normalmente não deveria fazer isso, e imagino que houve algum debate durante o desenvolvimento do kernel do Linux sobre se deveria permitir um mecanismo geral como clone() .

    
por 01.05.2015 / 04:19

Tags