Gostaria de compreender em detalhes a diferença entre fork () e vfork (). Não fui capaz de digerir a página do manual completamente.
Também gostaria de esclarecer o comentário de um dos meus colegas "No Linux atual, não há vfork (), mesmo se você chamá-lo, ele chamará internamente fork ()."
As páginas do manual são geralmente documentos de referência concisos. Wikipedia é um lugar melhor para obter explicações conceituais.
Fork duplica um processo: ele cria um processo filho que é quase idêntico ao processo pai (a diferença mais óbvia é que o novo processo tem um ID de processo diferente). Em particular, fork (conceitualmente) deve copiar toda a memória do processo pai.
Como isso é bastante caro, o vfork foi inventado para lidar com um caso especial comum onde a cópia não é necessária. Freqüentemente, a primeira coisa que o processo filho faz é carregar uma nova imagem do programa, então isso é o que acontece:
if (fork()) {
# parent process …
} else {
# child process (with a new copy of the process memory)
execve("/bin/sh", …); # discard the process memory
}
A chamada execve
carrega um novo programa executável e isso substitui o código do processo e a memória de dados pelo código do novo executável e uma nova memória de dados. Portanto, toda a cópia da memória criada por fork
foi inútil.
Assim, a chamada vfork
foi inventada. Não faz uma cópia da memória. Portanto, vfork
é barato, mas é difícil de usar, pois você deve ter certeza de não acessar nenhuma pilha do processo ou espaço de heap no processo filho. Observe que até a leitura pode ser um problema, porque o processo pai continua em execução. Por exemplo, este código está quebrado (pode ou não funcionar, dependendo se o filho ou o pai obtém uma fração de tempo primeiro):
if (vfork()) {
# parent process
cmd = NULL; # modify the only copy of cmd
} else {
# child process
execve("/bin/sh", "sh", "-c", cmd, (char*)NULL); # read the only copy of cmd
}
Desde a invenção do vfork, melhores otimizações foram inventadas. A maioria dos sistemas modernos, incluindo Linux, usa uma forma de cópia na gravação , onde as páginas na memória do processo não são copiadas no momento da chamada fork
, mas posteriormente quando o pai ou filho primeiro escreve na página. Ou seja, cada página começa como compartilhada e permanece compartilhada até que um dos processos grave nessa página; o processo de gravação obtém uma nova página física (com o mesmo endereço virtual). Copy-on-write torna o vfork praticamente inútil, já que fork
não fará nenhuma cópia nos casos em que vfork
seria utilizável.
O Linux mantém o vfork. A chamada de sistema fork
ainda deve fazer uma cópia da tabela de memória virtual do processo, mesmo que não copie a memória real; vfork
nem mesmo precisa fazer isso. A melhoria de desempenho é insignificante na maioria dos aplicativos.
As escalas fork()
e vfork()
são diferentes.
O fork()
syscall gera dois processos idênticos com memória separada. O vfork()
syscall gera dois processos que compartilham a mesma memória.
Com vfork()
o pai irá esperar que o filho termine. O pai herda das variáveis que o programa está compartilhando. Assim, depois que o filho foi chamado, todas as variáveis modificadas dentro do filho ainda serão modificadas dentro do pai.
Para mais informações clique em aqui