fork()foi a chamada do sistema UNIX original. Só pode ser usado para criar novos processos, não threads. Além disso, é portátil.
No Linux, clone()é uma nova chamada de sistema versátil que pode ser usada para criar um novo encadeamento de execução. Dependendo das opções passadas, o novo encadeamento de execução pode aderir à semântica de um processo UNIX, um encadeamento 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 arquivo, os vários namespaces, os manipuladores de sinais etc. são compartilhados ou copiados.
Como clone()é a chamada de superconjunto do sistema, a implementação do fork()wrapper de chamada do sistema na glibc realmente chama clone(), mas esse é um detalhe da implementação que os programadores não precisam conhecer. A fork()chamada real do sistema real ainda existe no kernel do Linux por motivos de compatibilidade com versões anteriores, mesmo que tenha se tornado redundante, porque programas que usam versões muito antigas do libc, ou outra libc além do glibc, podem usá-lo.
clone()também é usado para implementar a pthread_create()função POSIX para criar threads.
Programas portáteis devem chamar fork()e pthread_create(), não clone().
Este é o "clone ()" descrito ao fazer man 2 clone.
Se você ler essa página de manual o suficiente, verá o seguinte:
It is actually a library function layered on top of the
underlying clone() system call.
Aparentemente, você deve implementar o encadeamento usando a "função de biblioteca" em camadas na chamada do sistema com nome idêntico e confuso.
Eu escrevi um pequeno 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;
}
Compilou-o com:, c99 -Wall -Wextrae o executou strace -fpara ver o que as chamadas de bifurcação do sistema realmente fazem. Tirei isso de straceuma máquina Linux 2.6.18 (CPU x86_64):
Nenhuma chamada "fork" aparece na stracesaída. A clone()chamada que aparece na stracesaída tem argumentos muito diferentes do clone da página de manual. child_stack=0como o primeiro argumento é diferente de int (*fn)(void *).
Parece que a fork(2)chamada do sistema é implementada em termos do realclone() , assim como a "função de biblioteca" clone()é implementada. O realclone() tem um conjunto diferente de argumentos do clone da página de manual.
Simplisticamente, ambas as suas declarações aparentemente contraditórias sobre fork()e clone()estão corretas. O "clone" envolvido é diferente, no entanto.
"Na verdade, é uma função de biblioteca em camadas na parte superior da chamada do sistema clone () subjacente." - em geral, isso se aplica a todas as chamadas do sistema. Na verdade, os programadores praticamente sempre chamam funções na libc, nomeadas após a chamada do sistema. Isso ocorre porque fazer uma chamada real real ao sistema diretamente de C requer mágica específica da plataforma (geralmente forçando algum tipo de interceptação de CPU, depende da arquitetura ABI) e o código da máquina é melhor delegado à libc.
Celada
1
@ Celada - sim, concordou. É exatamente isso que man 2 clonediz exatamente dessa maneira, o que eu pensei que estava confundindo o problema e impedindo que o questionador obtivesse uma boa resposta.
precisa
2
Creio que a página de manual significa indicar que a lista de argumentos da clonefunção de biblioteca difere substancialmente da lista de argumentos aceita pela chamada do sistema subjacente. Especificamente, a chamada do sistema sempre retorna duas vezes na mesma pilha, da maneira tradicional fork; todos os argumentos relacionados à pilha filho são tratados estritamente no espaço do usuário. Veja, por exemplo, sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/…
zwol
1
Eu queria dar a sua melhor resposta, porque ela balança, mas fui influenciado pelo rebanho e fui com a primeira resposta. Ela ganha pontos pelo tempo de resposta. Obrigado pela sua explicação.
Gregg Leventhal
6
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 até 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()você pode escolher como aliasing ou copiá-las. Os threads correspondem ao alias, os processos correspondem à cópia. Ao especificar 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 tão geral como o clone().
Parece que há duas
clone()
coisas flutuando no Linux 2.6Há uma chamada do sistema:
Este é o "clone ()" descrito ao fazer
man 2 clone
.Se você ler essa página de manual o suficiente, verá o seguinte:
Aparentemente, você deve implementar o encadeamento usando a "função de biblioteca" em camadas na chamada do sistema com nome idêntico e confuso.
Eu escrevi um pequeno programa:
Compilou-o com:,
c99 -Wall -Wextra
e o executoustrace -f
para ver o que as chamadas de bifurcação do sistema realmente fazem. Tirei isso destrace
uma máquina Linux 2.6.18 (CPU x86_64):Nenhuma chamada "fork" aparece na
strace
saída. Aclone()
chamada que aparece nastrace
saída tem argumentos muito diferentes do clone da página de manual.child_stack=0
como o primeiro argumento é diferente deint (*fn)(void *)
.Parece que a
fork(2)
chamada do sistema é implementada em termos do realclone()
, assim como a "função de biblioteca"clone()
é implementada. O realclone()
tem um conjunto diferente de argumentos do clone da página de manual.Simplisticamente, ambas as suas declarações aparentemente contraditórias sobre
fork()
eclone()
estão corretas. O "clone" envolvido é diferente, no entanto.fonte
man 2 clone
diz exatamente dessa maneira, o que eu pensei que estava confundindo o problema e impedindo que o questionador obtivesse uma boa resposta.clone
função de biblioteca difere substancialmente da lista de argumentos aceita pela chamada do sistema subjacente. Especificamente, a chamada do sistema sempre retorna duas vezes na mesma pilha, da maneira tradicionalfork
; todos os argumentos relacionados à pilha filho são tratados estritamente no espaço do usuário. Veja, por exemplo, sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/…fork()
é apenas um conjunto específico de sinalizadores para a chamada do sistemaclone()
.clone()
é geral o suficiente para criar um "processo" ou um "encadeamento" ou até 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()
você pode escolher como aliasing ou copiá-las. Os threads correspondem ao alias, os processos correspondem à cópia. Ao especificar combinações intermediárias de sinalizadores paraclone()
, 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 tão geral como oclone()
.fonte