Por que "um fork é frequentemente seguido por um exec"? Você não pode simplesmente criar um novo processo no UNIX?
relate perguntas
-
Como posso desabilitar a barra de status de Zathura por padrão?
-
Os processos são encerrados quando um usuário bloqueia sua conta no Windows 10?
-
Se o Windows 7 não oferece suporte a WSL, o que é "Subsistema para aplicativos baseados em UNIX"?
-
Como remover a extensão do nome do caminho passado como {} em `find -exec`?
-
As guias no Apple Safari têm seus próprios processos?
fork()
cria um novo processo, que é uma cópia do processo pai. Então, se você fizesse apenasfork()
, você teria dois processos idênticos em execução. Portanto, para substituir o processo bifurcado por outro código, você precisa executarexec()
o que substitui o processo em execução no momento pelo arquivo executável especificado.O kernel do Linux é organizado dessa maneira. Você não tem uma única chamada de sistema que cria um novo processo e carrega um novo executável ao mesmo tempo. Você tem que fazer isso em duas etapas - primeiro crie um novo processo e, em seguida, carregue um novo executável nesse novo processo. (Embora você possa ter uma função de biblioteca em sua linguagem de programação que combina esses dois - por exemplo, há
spawn()
muitas variantes C).Às vezes
exec()
não é necessário, se apenas criar outra cópia do processo atual é tudo o que você deseja. Muitos daemons, por exemplo, fazem isso.Isso se deve a razões históricas: no início dos tempos havia apenas
fork
eexec
. Porque era fácil de implementar (de acordo com DMR: apenas 27 linhas de código de montagem PDP-7 parafork
! - veja, por exemplo , Afork()
in the road (Baumann, Appavoo, Krieger, Roscoe, 2019) - uma fonte secundária, embora faça referência a um primário fonte A Evolução do sistema de compartilhamento de tempo Unix (Ritchie, 1979) De qualquer forma, a verdadeira criação de processos diretos ab initio veio muito, muito, muito, muito mais tarde. (E não está no POSIX, possivelmente?)O fato de que uma verdadeira API de criação direta de processos veio muito mais tarde afeta a programação Unix até hoje. Porque centenas de livros, manuais, tutoriais, apresentações de slides e cursos foram escritos explicando
fork
eexec
ensinados a estudantes e programadores por décadas como a maneira de fazer criação/controle de processos em Unix e essa extensa herança persiste na forma como o código está escrito até hoje .Ah, aqui está A Evolução do Sistema Unix de Compartilhamento de Tempo (Ritchie, 1979) . Role para baixo até a página 6 para ver: "O controle de processo em sua forma moderna foi projetado e implementado em alguns dias. ..... Na verdade, a chamada de bifurcação do PDP-7 exigiu precisamente 27 linhas de código de montagem."
Porque um exec não cria um processo, e o linux não tem um único syscall para criar processo e carregar executável porque isso só funciona no caso trivial de criar um processo com novo executável sem recursos preexistentes. Se você quiser fazer algo além do caso trivial, a complexidade aumenta rapidamente e fica mais fácil ter etapas separadas de 'criar processo' e 'iniciar executável' com a capacidade de manipular o processo entre elas. Veja https://lwn.net/Articles/360556/ para uma discussão sobre isso.
O Unix, voltando às versões mais antigas, resolveu isso usando fork para criar uma duplicata do processo pai dedicado à configuração do ambiente, que carrega o novo executável, uma vez concluído. O processo filho existe em um estado temporário de acesso a todos os recursos do processo pai, mas de execução no processo filho. Essa abordagem tem algumas vantagens:
Uma perspectiva ligeiramente diferente da maioria das respostas existentes "fork-shaming" ... ;)
Originalmente era provavelmente, como @davidbak mencionou, tão tentadoramente fácil de fazer dessa maneira. Mas tendo trabalhado muito com
fork
/exec
(e também muitas vezes apenas comfork
, para multiprocessamento), definitivamente existem razões pelas quais essa maneira de trabalhar ainda está viva e chutando, e não delegada ao nevoeiro da história:fork
semântica e oferecê-la como parte da linguagem. Portanto, toda linguagem tem um método relativamente trivial (comparado ao multithreading em processo) de oferecer pelo menos multiprocessamento para seus usuários.fork
semântica, nunca mais precisará aprender mais sobre o novo ambiente - é sempre tão simples quanto em qualquer outra linguagem.exec
qualquer maneira. Ele nos permite substituir a imagem do processo atual (ou seja, o executável que está sendo executado) por algo diferente. Isso torna limpo, digamos, ter algum script ou programa que prepare algum tipo de ambiente e depois execute outra coisa, enquanto desaparece da cena. Não apenas libera recursos (RAM, mas também espaço na tabela de processos e assim por diante), mas deixa muito claro para qualquer pessoa envolvida ou olhando para ele que o antigo pai não desempenhará mais nenhum papel no futuro . Muitas vezes você encontra isso embash
scripts bem escritos, que liberam os recursos dobash
intérprete ao iniciar sua "carga útil".Além disso:
fork
+exec
seguindo um ao outro. Não é como se você tivesse que fazer muitas coisas no meio (ou qualquer coisa, na verdade), a menos que você precise.fork+exec
. Observe que aqui vemos a complexidade já levantando sua cabeça feia; O Linux também tem uma função clone3 que substituiclone
e torna a interface um pouco mais fácil ou mais conveniente (usandostructs
ao invés de tantos sinalizadores).Não, você não pode criar um novo processo no UNIX, você só pode duplicar seu processo atual (usando
fork
). Se você deseja que o novo processo faça algo diferente do que o processo atual está fazendo, você o substitui (usandoexec
).Você não precisa
fork
antes de ligarexec
. Há um uso comum em scripts que iniciam uma sessão de login (.xinitrc
e similares) onde você configura variáveis de ambiente e inicia tarefas em segundo plano (comossh-agent
) e, em seguida, executa o gerenciador de sessões. Não há mais nada para o script de inicialização fazer depois de iniciar o gerenciador de sessões, para que vocêexec
libere os recursos atribuídos à execução do script de inicialização. O pai do script de inicialização não tem conhecimento dessa substituição - o PID permanece o mesmo - então eles continuam esperando que esse filho morra antes de executar suas ações de limpeza.