Eu estava procurando encontrar a diferença entre esses quatro no Google e esperava que houvesse uma quantidade enorme de informações sobre isso, mas realmente não havia uma comparação sólida entre as quatro chamadas.
Comecei a tentar compilar uma espécie de visão geral básica das diferenças entre essas chamadas de sistema e aqui está o que recebi. Todas essas informações estão corretas / estou perdendo alguma coisa importante?
Fork
: A chamada de fork basicamente faz uma duplicata do processo atual, idêntica em quase todos os aspectos (nem tudo é copiado, por exemplo, nos limites de recursos em algumas implementações, mas a idéia é criar uma cópia o mais próxima possível).
O novo processo (filho) obtém um ID de processo diferente (PID) e tem o PID do processo antigo (pai) como seu PID pai (PPID). Como os dois processos agora estão executando exatamente o mesmo código, eles podem dizer qual é o código de retorno do fork - a criança recebe 0, o pai recebe o PID da criança. Isso é tudo, é claro, supondo que a chamada da bifurcação funcione - caso contrário, nenhum filho será criado e o pai receberá um código de erro.
Vfork
: A diferença básica entre vfork e fork é que, quando um novo processo é criado com vfork (), o processo pai é suspenso temporariamente e o processo filho pode pedir emprestado o espaço de endereço do pai. Esse estranho estado de coisas continua até que o processo filho saia ou chame execve (), quando o processo pai continua.
Isso significa que o processo filho de um vfork () deve ter cuidado para evitar alterações inesperadas nas variáveis do processo pai. Em particular, o processo filho não deve retornar da função que contém a chamada vfork () e não deve chamar exit () (se precisar sair, deve usar _exit (); na verdade, isso também é verdade para o filho de um garfo normal ()).
Exec :
A chamada exec é uma maneira de substituir basicamente todo o processo atual por um novo programa. Ele carrega o programa no espaço de processo atual e o executa a partir do ponto de entrada. exec () substitui o processo atual por um executável apontado pela função. O controle nunca retorna ao programa original, a menos que haja um erro exec ().
Clone :
Clone, como fork, cria um novo processo. Diferentemente da bifurcação, essas chamadas permitem que o processo filho compartilhe partes de seu contexto de execução com o processo de chamada, como espaço de memória, tabela de descritores de arquivo e tabela de manipuladores de sinal.
Quando o processo filho é criado com o clone, ele executa o aplicativo de função fn (arg). (Isso difere da bifurcação, onde a execução continua no filho a partir do ponto da chamada de bifurcação original.) O argumento fn é um ponteiro para uma função chamada pelo processo filho no início de sua execução. O argumento arg é passado para a função fn.
Quando o aplicativo da função fn (arg) retorna, o processo filho termina. O número inteiro retornado por fn é o código de saída para o processo filho. O processo filho também pode terminar explicitamente chamando exit (2) ou após receber um sinal fatal.
Informações obtidas:
- Diferenças entre fork e exec
- http://www.allinterview.com/showanswers/59616.html
- http://www.unixguide.net/unix/programming/1.1.2.shtml
- http://linux.about.com/library/cmd/blcmdl2_clone.htm
Obrigado por tomar o tempo para ler este ! :)
fork()
que está no Linux e provavelmente todos os BSDs) emprestar o espaço de endereço de seus pais. Tudo o que faz, além de chamarexecve()
ou_exit()
, tem um grande potencial para atrapalhar os pais. Em particular,exit()
chamaatexit()
manipuladores e outros "finalizadores", por exemplo: libera fluxos stdio. O retorno de umvfork()
filho potencialmente (com a mesma ressalva de antes) prejudicaria a pilha dos pais.fork
syscall?Respostas:
vfork()
é uma otimização obsoleta. Antes de um bom gerenciamento de memória,fork()
fazia uma cópia completa da memória dos pais, por isso era muito caro. como em muitos casos afork()
foi seguido porexec()
, que descarta o mapa de memória atual e cria um novo, era uma despesa desnecessária. Hoje em dia,fork()
não copia a memória; é simplesmente definido como "copiar na gravação", entãofork()
+exec()
é tão eficiente quantovfork()
+exec()
.clone()
é o syscall usado porfork()
. com alguns parâmetros, cria um novo processo, com outros, cria um encadeamento. a diferença entre eles é justamente quais estruturas de dados (espaço na memória, estado do processador, pilha, PID, arquivos abertos etc.) são compartilhadas ou não.fonte
vfork
evita a necessidade de comprometer temporariamente muito mais memória para que você possa executarexec
, e ainda é mais eficiente do quefork
, mesmo que não seja tão alto quanto possível. Assim, é possível evitar ter que comprometer demais a memória, para que um grande programa possa gerar um processo filho. Portanto, não apenas um aumento de desempenho, mas pode torná-lo possível.exec
.execve()
substitui a imagem executável atual por outra carregada de um arquivo executável.fork()
cria um processo filho.vfork()
é uma versão histórica otimizada dofork()
, destinada a ser usada quandoexecve()
for chamada diretamente depoisfork()
. Acabou funcionando bem em sistemas não-MMU (ondefork()
não pode funcionar de maneira eficiente) e aofork()
processar processos com um enorme espaço de memória para executar algum programa pequeno (pense em JavaRuntime.exec()
). O POSIX padronizou oposix_spawn()
substituição desses dois últimos usos mais modernos dovfork()
.posix_spawn()
faz o equivalente afork()/execve()
, e também permite algum fd malabarismo no meio. É suposto substituirfork()/execve()
, principalmente para plataformas não-MMU.pthread_create()
cria um novo thread.clone()
é uma chamada específica do Linux, que pode ser usada para implementar qualquer coisa defork()
atépthread_create()
. Dá muito controle. Inspirado emrfork()
.rfork()
é uma chamada específica do plano 9. Deveria ser uma chamada genérica, permitindo vários graus de compartilhamento, entre processos e threads completos.fonte
fork()
- cria um novo processo filho, que é uma cópia completa do processo pai. Os processos filho e pai usam diferentes espaços de endereço virtual, inicialmente preenchidos pelas mesmas páginas de memória. Então, à medida que os dois processos são executados, os espaços de endereço virtual começam a diferir cada vez mais, porque o sistema operacional realiza uma cópia lenta das páginas de memória que estão sendo gravadas por um desses dois processos e atribui cópias independentes das páginas modificadas do memória para cada processo. Essa técnica é chamada de Copy-On-Write (COW).vfork()
- cria um novo processo filho, que é uma cópia "rápida" do processo pai. Ao contrário da chamada do sistemafork()
, os processos filho e pai compartilham o mesmo espaço de endereço virtual. NOTA! Usando o mesmo espaço de endereço virtual, pai e filho usam a mesma pilha, o ponteiro da pilha e o ponteiro da instrução, como no caso do clássicofork()
! Para evitar interferência indesejada entre pai e filho, que usam a mesma pilha, a execução do processo pai é congelada até que o filho chameexec()
(crie um novo espaço de endereço virtual e uma transição para uma pilha diferente) ou_exit()
(finalização da execução do processo )vfork()
é a otimizaçãofork()
"fork-and-exec". Pode ser executado 4-5 vezes mais rápido que ofork()
porque, ao contrário dofork()
(mesmo com o COW em mente), a implementação da dovfork()
a chamada do sistema não inclui a criação de um novo espaço de endereço (a alocação e configuração de novos diretórios de página).clone()
- cria um novo processo filho. Vários parâmetros dessa chamada do sistema especificam quais partes do processo pai devem ser copiadas no processo filho e quais partes serão compartilhadas entre eles. Como resultado, essa chamada do sistema pode ser usada para criar todos os tipos de entidades de execução, iniciando nos encadeamentos e finalizando por processos completamente independentes. De fato, aclone()
chamada do sistema é a base usada para a implementaçãopthread_create()
e toda a família dasfork()
chamadas do sistema.exec()
- redefine toda a memória do processo, carrega e analisa o binário executável especificado, configura uma nova pilha e passa o controle para o ponto de entrada do executável carregado. Essa chamada do sistema nunca retorna o controle ao chamador e serve para carregar um novo programa no processo já existente. Essa chamada de sistema com a chamada defork()
sistema em conjunto formam um modelo clássico de gerenciamento de processos UNIX chamado "fork-and-exec".fonte
vfork
são tão fracos que seria legal fazervfork
um sinônimofork
(e o POSIX.1-2008 removevfork
completamente as especificações). Se você testar seu código em um sistema que os sinonimiza (por exemplo, a maioria dos BSDs pós-4.4, exceto o NetBSD, os kernels Linux pré-2.2.0-pre6 do Linux, etc.), pode funcionar mesmo se você violar ovfork
contrato e explodir se você executá-lo em outro lugar. Alguns daqueles que simulá-lo comfork
(por exemplo, OpenBSD) ainda garantir o pai não continuar funcionando até que a criançaexec
s ou_exit
s. É ridiculamente não portátil.O fork (), vfork () e o clone () chamam o do_fork () para fazer o trabalho real, mas com parâmetros diferentes.
Para fork, o filho e o pai têm a tabela de páginas VM independente, mas, como a eficiência, o fork realmente não copia nenhuma página, apenas define todas as páginas graváveis como somente leitura para o processo filho. Portanto, quando o processo filho quiser escrever algo nessa página, ocorrerá uma exceção de página e o kernel alocará uma nova página clonada da página antiga com permissão de gravação. Isso é chamado "copiar na gravação".
Para o vfork, a memória virtual é exatamente por filho e pai - apenas por isso, pai e filho não podem acordar simultaneamente, pois eles se influenciarão. Portanto, o pai dormirá no final de "do_fork ()" e acordará quando a criança chamar exit () ou execve () desde então, ela possuirá a nova tabela de páginas. Aqui está o código (em do_fork ()) que o pai dorme.
Aqui está o código (em mm_release () chamado por exit () e execve ()) que acorda o pai.
Para sys_clone (), é mais flexível, pois você pode inserir qualquer clone_flags nele. Então pthread_create () chame essa chamada de sistema com muitos clone_flags:
int clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL | CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID | CLONE_SYSVSEM);
Resumo: o fork (), vfork () e clone () criarão processos filhos com montagem diferente de compartilhamento de recursos com o processo pai. Também podemos dizer que o vfork () e o clone () podem criar threads (na verdade, são processos, pois possuem task_struct independente), pois compartilham a tabela de páginas da VM com o processo pai.
fonte
no fork (), o processo filho ou pai será executado com base na seleção da CPU. Mas no vfork (), certamente o filho será executado primeiro. após o término do filho, o pai será executado.
fonte
vfork()
apenas pode ser implementado comofork()
.pid
) - o sistema operacional pode agendar o novo processo para ser executado em paralelo se algo assim fizer sentido (por exemplo, vários processadores). Se, por algum motivo, você precisar que esses processos sejam executados em uma ordem serial específica, precisará de uma sincronização adicional que o bifurcação não fornece; francamente, você provavelmente nem iria querer um garfo em primeiro lugar.vfork()
, a criança corre primeiro. Está nas páginas do manual; a execução dos pais é suspensa até a criança morrer ou morrerexec
. E ninjalj procura o código fonte do kernel. Não há maneira de implementarvfork()
comofork()
porque passam argumentos diferentes parado_fork()
dentro do kernel. Você pode, no entanto, implementarvfork
com oclone
syscall