Segundo a Wikipedia (o que pode estar errado)
Quando uma chamada do sistema fork () é emitida, uma cópia de todas as páginas correspondentes ao processo pai é criada, carregada em um local de memória separado pelo SO para o processo filho. Mas isso não é necessário em certos casos. Considere o caso em que um filho "
exec
" executa uma chamada do sistema (usada para executar qualquer arquivo executável de um programa C) ou sai logo após ofork()
. Quando o filho é necessário apenas para executar um comando para o processo pai, não há necessidade de copiar as páginas do processo pai, poisexec
substitui o espaço de endereço do processo que o invocou pelo comando a ser executado.Nesses casos, é utilizada uma técnica chamada cópia na gravação (COW). Com essa técnica, quando ocorre uma bifurcação, as páginas do processo pai não são copiadas para o processo filho. Em vez disso, as páginas são compartilhadas entre o filho e o processo pai. Sempre que um processo (pai ou filho) modifica uma página, é feita apenas uma cópia separada dessa página específica para o processo (pai ou filho) que executou a modificação. Esse processo usará a página recém-copiada em vez da compartilhada em todas as referências futuras. O outro processo (aquele que não modificou a página compartilhada) continua usando a cópia original da página (que agora não é mais compartilhada). Essa técnica é chamada de copiar na gravação, pois a página é copiada quando algum processo é gravado nela.
Parece que quando um dos processos tenta gravar na página, uma nova cópia da página é alocada e atribuída ao processo que gerou a falha da página. A página original é marcada como gravável posteriormente.
Minha pergunta é: o que acontece se a fork()
chamada é chamada várias vezes antes de qualquer um dos processos tentar gravar em uma página compartilhada?
pmap -XX PID
oucat /proc/PID/smap
.Respostas:
Nada de especial acontece. Todos os processos estão compartilhando o mesmo conjunto de páginas e cada um obtém sua própria cópia privada quando deseja modificar uma página.
fonte
O comportamento do fork () depende se o sistema * nix possui uma MMU ou não. Em um sistema não-MMU (como os primeiros PDP-11s), a chamada do sistema fork () copiava toda a memória dos pais de cada filho. Em um sistema * nix baseado em MMU, o kernel marca todas as páginas que não são de pilha como R / O e as compartilha entre pai e filho. Então, quando um dos processos grava em qualquer página, o MMU captura a tentativa, o kernel aloca uma página gravável e atualiza as tabelas de páginas do MMU para apontar para a página agora gravável. Esse comportamento de copiar na gravação fornece uma aceleração, pois inicialmente apenas uma pilha privada precisa ser alocada e clonada para cada processo filho.
Se você executar algum código pai entre cada chamada fork (), os processos filhos resultantes serão diferentes pelas páginas que foram alteradas pelo pai. Por outro lado, se o pai simplesmente emitir várias chamadas fork (), por exemplo, em um loop, os processos filhos serão quase idênticos. Se uma variável de loop local for usada, isso será diferente na pilha de cada criança.
fonte
Quando o sistema pré-forma uma bifurcação, normalmente (isso pode depender da implementação) também marca as páginas como somente leitura e marca o processo pai como o mestre dessas páginas.
Ao tentar gravar nessas páginas, ocorre uma falha de página e o sistema operacional assume o controle, copiando toda a lista de páginas ou apenas as alteradas (novamente, dependendo da implementação), para que o processo de gravação tenha uma cópia gravável.
Quando há vários processos bifurcados no mesmo, quando o processo "mestre" grava em sua memória, os outros processos obtêm suas páginas equivalentes copiadas.
fonte