Conceitos de sistema operacional e APUE dizem
Com vfork (), o processo pai é suspenso e o processo filho usa o espaço de endereço do pai. Como o vfork () não usa a cópia na gravação, se o processo filho alterar alguma página do espaço de endereço do pai, as páginas alteradas ficarão visíveis para o pai depois que ele for reiniciado. Portanto, vfork () deve ser usado com cuidado para garantir que o processo filho não modifique o espaço de endereço do pai.
O vfork () deve ser usado quando o processo filho chama exec () ou exit () imediatamente após a criação.
Como vou entender a última frase?
Quando um processo filho criado por vfork()
chamadas exec()
, não exec()
modifica o espaço de endereço do processo pai, carregando o novo programa?
Quando um processo filho criado por vfork()
chamadas exit()
, exit()
não modifica o espaço de endereço do processo pai ao finalizar o filho?
Eu tenho preferência para Linux.
Obrigado.
posix_spawn
. É significativamente mais difícil escrever o código correto usando doposix_spawn
que com o antigofork
e, se você tentar, pode se deparar com uma parede de tijolos por não haver uma ação ou atributo de arquivo que faça o que você precisa fazer entrefork
eexec
. E não é garantido que tenha uma eficiência semelhante ao vfork, portanto nem sequer resolve o problema que as pessoas querem que ele resolva.posix_spawn
possa faltar a funcionalidade desejada (você pode resolver isso por meio de um programa auxiliar intermediário, escrito em C ou em shell script inline-on-cmdline), qualquer tentativa de conseguir o que desejavfork
invoca um comportamento indefinido perigoso. A especificação paravfork
não permite que funções aleatórias de chamada configurem o estado que o filho herdará antesexecve
e tentativas de fazê-lo podem corromper o estado do pai.posix_spawn
executa aproximadamente o mesmo quevfork
na maioria das condições. Aqueles em que há uma diferença tendem a ser exatamente os casos em quevfork
é altamente inseguro: onde existem manipuladores de sinal instalados que precisam impedirposix_spawn
a execução no filho antes do exec.Quando você chama
vfork()
, um novo processo é criado e esse novo processo empresta a imagem do processo pai, com exceção da pilha. O processo filho recebe uma nova estrela de pilha, no entanto, não permite areturn
partir da função que chamouvfork()
.Enquanto o filho estiver em execução, o processo pai será bloqueado, pois o filho emprestou o espaço de endereço do pai.
Independentemente do que você faz, tudo o que acessa apenas a pilha modifica apenas a pilha privada da criança. Se você modificar dados globais, isso modificará os dados comuns e, portanto, também afetará o pai.
Coisas que modificam dados globais são, por exemplo:
chamando malloc () ou free ()
usando stdio
modificando configurações de sinal
modificando variáveis que não são locais para a função que chamou
vfork()
....
Depois que você liga
_exit()
(importante, nunca ligaexit()
), a criança é encerrada e o controle é devolvido aos pais.Se você chamar qualquer função da
exec*()
família, um novo espaço de endereço será criado com o novo código do programa, novos dados e uma parte da pilha do pai (veja abaixo). Uma vez pronto, o filho não pede mais o espaço de endereço do filho, mas usa um próprio espaço de endereço.O controle é devolvido ao pai, pois seu espaço de endereço não está mais sendo usado por outro processo.
Importante: No Linux, não há
vfork()
implementação real . O Linux é implementado comvfork()
base nofork()
conceito Copy on Write, introduzido pelo SunOS-4.0 em 1988. Para fazer os usuários acreditarem que usamvfork()
, o Linux apenas configura dados compartilhados e suspende o pai enquanto o filho não chamava_exit()
ou uma dasexec*()
funções.Portanto, o Linux não se beneficia do fato de que um real
vfork()
não precisa configurar uma descrição do espaço de endereço para o filho no kernel. Isso resulta em umvfork()
que não é mais rápido quefork()
. Em sistemas que implementam um realvfork()
, normalmente é 3x mais rápido quefork()
e afeta o desempenho de shells que usamvfork()
-ksh93
, o recenteBourne Shell
ecsh
.A razão pela qual você nunca deve ligar
exit()
dovfork()
filho ed é queexit()
libera o stdio caso haja dados não liberados do momento antes da chamadavfork()
. Isso pode causar resultados estranhos.BTW:
posix_spawn()
é implementado em cima devfork()
, portanto,vfork()
não será removido do sistema operacional. Foi mencionado que o Linux não usavfork()
paraposix_spawn()
.Para a pilha, há pouca documentação, aqui está o que a página de manual do Solaris diz:
Portanto, a implementação pode fazer o que quiser. A implementação Solaris usa memória compartilhada para o quadro de pilha da chamada de função
vfork()
. Nenhuma implementação concede acesso a partes mais antigas da pilha do pai.fonte
posix_spawn()
no Linuxvfork()
. Ambos o implementam em cima de__clone()
.vfork()
apenas liga,clone()
certo? É literalmente uma linha no kernel.vfork
efork
no Linux, ele estará fazendo algo errado.