Não tenho muita experiência, apenas tentando me envolver nos processos, como eles interpretam o hardware no nível do usuário.
Portanto, quando um comando é acionado a partir de um shell, fork()
herda um processo filho e exec()
carrega o processo filho na memória e é executado.
- Se o processo filho contiver todos os atributos do processo pai (que é o processo original), qual é a necessidade desse processo filho? O processo original também pode ter sido carregado na memória.
- Isso
fork
eexec
conceito se aplicam a todo o programa executável no UNIX? Como para o shell script também ou apenas para comandos? Também se aplica a comandos internos do shell? - Quando a cópia na gravação é usada se eu executar um comando / script?
Desculpe por fazer muitas perguntas ao mesmo tempo, mas todas essas perguntas vêm à minha mente ao pensar em qualquer execução de comando.
Respostas:
Não é bem assim.
fork()
clona o processo atual, criando um filho idêntico.exec()
carrega um novo programa no processo atual, substituindo o existente.A necessidade é porque o processo pai ainda não deseja finalizar; ele quer que um novo processo seja executado e faça algo ao mesmo tempo em que continua sendo executado.
Para comandos externos, o shell faz
fork()
isso para que o comando seja executado em um novo processo. Builtins são apenas executados diretamente pelo shell. Outro comando notável é oexec
que informa o shell aoexec()
programa externo sem primeirofork()
. Isso significa que o próprio shell é substituído pelo novo programa e, portanto, não está mais lá para que o programa retorne quando sair. Se você diz,exec true
e depois/bin/true
irá substituir o seu shell, e imediatamente saída, não deixando nada em execução no seu terminal mais, então ele será fechado.Na era da pedra,
fork()
na verdade , era necessário copiar toda a memória do processo de chamada para o novo processo. Copy on Write é uma otimização em que as tabelas de páginas são configuradas para que os dois processos comecem a compartilhar toda a mesma memória e apenas as páginas que são gravadas por qualquer processo são copiadas quando necessário.fonte
cd
ouread
podem funcionar. A falta de bifurcação também torna os componentes internos muito mais rápidos que os comandos externos.execve()
para se sobrepor a um código diferente.fork()
e seexec()
aplicam a todos os executáveis - de fato, junto com argc e argv, e pipes, fork e exec são o que diferenciam o Unix de outros sistemas operacionais.fork()
Existem algumas especializações ou generalizações de existem, como BSDvfork()
, Plan 9rfork()
e Linux 'clone()
, mas o principal permanece o mesmo.malloc()
, ou mesmo variáveis de escopo estáticas ou globais) podem ser "cópia na gravação". Quando um processo filho é criado com umfork()
Na chamada, o kernel configuraria o processo filho para ter exatamente as mesmas páginas de memória que a pilha e a pilha que o processo pai. Se o hardware (unidade de gerenciamento de memória) detectar uma gravação do heap ou da pilha, o kernel obterá uma nova página física de memória, copiará a página do pai na nova página e mapeará essa nova página na pilha ou pilha do processo filho. Isso constitui uma otimização, pois o kernel gasta menos tempo configurando mapeamentos de página do que faria para copiar a pilha e o heap completamente para o processo filho.fonte
Esta pergunta é respondida de maneira ilustrativa, examinando as implementações mais antigas do Unix, que tinham que funcionar sob severas restrições de memória e tinham apenas um processo de execução no espaço de memória / endereço por vez.
A multitarefa foi obtida trocando um processo para disco e trocando um processo diferente.
Agora, a
fork
chamada do sistema era quase a mesma: ela trocou um processo para o disco, mas, em vez de trocar outro processo, deu à cópia na memória outro ID de processo e retornou a ele. E esse foi um momento oportuno para esse processo decidir apenasexec
para outro executável, afinal.fork
+exec
portanto, na verdade, não ocorreu uma sobrecarga perceptível sobre a desova: você tinha que trocar seu processo para o disco de qualquer maneira e tinha a imagem antiga do processo em locais de memória viáveis.Com quantidades crescentes de unidades de gerenciamento de memória e memória disponíveis e vários processos na memória, o custo inicialmente insignificante de um garfo se tornou um incômodo para algumas arquiteturas: assim
vfork
nasceu.fonte
Para tornar isso o mais fácil de entender possível, usarei uma analogia. Vamos assar uma torta!
Pegamos o livro de receitas e começamos a ler e a preparar uma torta de ruibarbo com morango (a minha favorita), com uma crosta feita à mão. Quase tudo o que precisamos está na cozinha, exceto os ovos e as frutas, mas como vivemos em uma fazenda e as frutas estão na estação, isso não é um problema. o problema é que o forno está quebrado e não há tempo suficiente para fazer tudo. Não seria bom ter mais de um de mim?
fork () para o resgate. Agora há dois de mim. e nós dois vamos para a cozinha para começar a fazer a massa de torta. oops. Então, olhamos para o retorno do fork. Eu tenho um grande número que ele tem zero, então vou para a cozinha enquanto ele se dirige para o galinheiro e o jardim. Quando passo pelo forno, bifurco () novamente, observe o valor de retorno: que chatice, fiquei zero. Ele continua com a farinha enquanto eu encaro o forno quebrado. Abro a porta, sem luz, fecho a porta. Alguém sabe como consertar um forno?
exec () para o resgate. Pego o voltímetro no cinto de ferramentas, a lâmpada pode ser diagnóstica, então verifico a potência. enquanto caminho até o painel do disjuntor, vejo um colega colhendo ruibarbo. Que nojo! Eu prefiro torta de chocolate com seda.
fonte