Por que o mecanismo de criação de processo padrão é bifurcado?

46

A chamada do sistema UNIX para criação de processo, fork (), cria um processo filho, copiando o processo pai. Meu entendimento é que isso quase sempre é seguido por uma chamada para exec () para substituir o espaço de memória do processo filho (incluindo o segmento de texto). Copiar o espaço de memória dos pais no fork () sempre pareceu um desperdício para mim (embora eu perceba que o desperdício pode ser minimizado, fazendo com que os segmentos de memória sejam copiados na gravação para que apenas os ponteiros sejam copiados). Enfim, alguém sabe por que essa abordagem de duplicação é necessária para a criação do processo?

Ellen Spertus
fonte
3
Observe que a fork(2)página de manual no Linux diz: Under Linux, fork() is implemented using copy-on-write pages, so the only penalty that it incurs is the time and memory required to duplicate the parent's page tables, and to create a unique task structure for the child. Imagino (mas não sei ao certo) que esse é o caso de outros sabores modernos do Unix.
Larsks
4
O original, PDP-11 Unix, realmente copiava todos os bytes de um processo bifurcado: mas tinha apenas 64 KB de executável e no máximo 64 KB de dados, por isso não era um fardo enorme, mesmo em 1975. Eu faria acho que TODOS os unix e unix-like, desde 1990, tiveram segmentos de texto de copiar-em-escrever, então nem sei por que livros e artigos propagam mais "problemas de desempenho com garfo".
11558 Bruce Ediger
Atualmente, o fork é implementado de maneira semelhante ao vfork ( openbsd.org/cgi-bin/… ). É eficiente, não se preocupe.
274 Aki
Observe também que há muito uso em que você não executa após uma bifurcação (ou pelo menos não executa imediatamente): pense em pipes e servidores da web.
Jfg956
Você pode pensar que seria lento. Mas como o @cjm diz que observe a alternativa que a Microsoft usa o CreateProcess, eles tiveram que implementar threads antecipadamente (pode ser a única coisa na qual lideram), porque o CreateProcess é lento. (Eles também precisavam de threads porque selectestavam quebrados, mas isso é outra história).
Ctrl-alt-delor

Respostas:

57

É para simplificar a interface. A alternativa forke execseria algo como a função CreateProcess do Windows . Observe quantos parâmetros CreateProcesspossui e muitos deles são estruturas com ainda mais parâmetros. Isso ocorre porque tudo o que você deseja controlar sobre o novo processo deve ser passado CreateProcess. De fato, CreateProcesscomo não possui parâmetros suficientes, a Microsoft precisou adicionar CreateProcessAsUser e CreateProcessWithLogonW .

Com o fork/execmodelo, você não precisa de todos esses parâmetros. Em vez disso, certos atributos do processo são preservados exec. Isso permite que você forkaltere os atributos de processo desejados (usando as mesmas funções que você usaria normalmente) e, em seguida exec ,. No Linux, forknão possui parâmetros e execvepossui apenas 3: o programa a ser executado, a linha de comando a ser fornecida e seu ambiente. (Existem outras execfunções, mas são apenas wrappers execvefornecidos pela biblioteca C para simplificar casos de uso comuns.)

Se você deseja iniciar um processo com um diretório atual diferente: fork, chdir, exec.

Se você deseja redirecionar stdin / stdout:, forkfeche / abra arquivos exec,.

Se você quiser usuários Switch: fork, setuid, exec.

Todas essas coisas podem ser combinadas conforme necessário. Se alguém criar um novo tipo de atributo de processo, você não precisará alterar forke exec.

Como os larsks mencionaram, a maioria dos Unixes modernos usa cópia na gravação, portanto fork, não envolve sobrecarga significativa.

cjm
fonte
16
Excelente explicação. "Quem não entende o UNIX está condenado a reinventá-lo mal." - Henry Spencer
Kyle Jones
1
Obrigado! Você tem alguma referência, por acaso?
Ellen Spertus
1
@Aki, não, CreateProcess () literalmente cria um novo processo e o constrói a partir do zero, sem bifurcação.
Psusi
2
Mas não deve haver algum equivalente de CreateProcess () em algum lugar do Unix? Caso contrário, como o primeiro processo é criado? Ao contrário de um deus criador mitológico, o primeiro processo não pode se forçar do nada. ;-)
Steven segunda-feira
2
@StevenMonday, sim, mas está no código de inicialização do kernel e não é acessível externamente. Ele não precisa de todos esses parâmetros porque quase tudo é codificado. Ele só pode criar o ID do processo 1, também conhecido como processo init. Depois disso, os processos são criados apenas por bifurcação.
Cjm
5

Além da resposta do cjm, a Especificação Unix Única define uma função denominada vfork(). Essa função funciona como bifurcação, exceto que o processo bifurcado tem um comportamento indefinido se fizer algo diferente de tentar chamar uma função execut exec familly ou chamar _exit().

Portanto, praticamente o único uso com comportamento definido é:

pid_t ret = vfork();
if(ret == 0)
{
    exec(...);
    _exit(EXIT_FAILURE); //in case exec failed for any reason.
}

Então o que vforkfaz? É um é barato fork. Nas implementações sem copiar na gravação, o processo resultante compartilhará espaço de memória com o processo original (daí o comportamento indefinido). Nas implementações com cópia na gravação, vforké permitido ser idêntico fork(), pois as implementações de cópia na gravação são rápidas.

Há também a posix_spawnfunção opcional (e uma posix_spawnpfunção) que pode criar diretamente um novo processo. (Também é permitido implementá-los com uma chamada de biblioteca usando forke exec, e um exemplo de implementação é fornecido.)

Kevin Cathcart
fonte