Como exatamente o shell típico “fork fork” se chama duas vezes?

15

Depois de passar pelas famosas Perguntas do Fork Bomb no Askubuntu e muitos outros sites do Stack Exchange, eu não entendo muito bem o que todo mundo está dizendo como é óbvio.

Muitas respostas ( Melhor exemplo ) dizem o seguinte:

"{:|: &} means run the function : and send its output to the : function again "

Bem, o que exatamente é a saída de : ? O que está sendo passado para o outro : ?

E também:

Essentially you are creating a function that calls itself twice every call and doesn't have any way to terminate itself.

Como exatamente isso é executado duas vezes ? Na minha opinião, nada é passado para o segundo : até que o primeiro : termine sua execução, o que na verdade nunca terminará.

Em C , por exemplo,

foo()
{
    foo();
    foo(); // never executed 
}

o segundo foo() não é executado, apenas porque o primeiro foo() nunca termina.

Estou pensando que a mesma lógica se aplica a :(){ :|: & };: e

:(){ : & };:

faz o mesmo trabalho que

:(){ :|: & };:

Por favor, ajude-me a entender a lógica.

    
por Severus Tux 16.10.2016 / 19:35

1 resposta

26

A tubulação não exige que a primeira instância termine antes que a outra seja iniciada. Na verdade, tudo o que está realmente fazendo é redirecionar o stdout da primeira instância para o stdin do segundo, para que eles possam ser executados simultaneamente (como devem ser para o bomba de garfo para o trabalho).

Well, What exactly is the output of : ? what is being passed to the other : ?

':' não está escrevendo nada para o outro ':' instância, está apenas redirecionando o stdout para o stdin da segunda instância. Se ele escreve alguma coisa durante sua execução (o que nunca acontecerá, já que ela não faz nada além de bifurcação), ela iria para o stdin da outra instância.

Isso ajuda a imaginar stdin e stdout como uma pilha:

O que estiver escrito no stdin será empilhado para quando o programa decidir ler, enquanto o stdout funciona da mesma maneira: uma pilha que você pode escrever para, assim outros programas podem ler quando quiserem.

Dessa forma, é fácil imaginar situações como um pipe que não tem nenhuma comunicação acontecendo (duas pilhas vazias) ou gravações e leituras não sincronizadas.

How exactly is that executed twice? In my opinion, nothing is passed to the second : until the first : finishes its execution, which actually will never end.

Como estamos apenas redirecionando a entrada e a saída das instâncias, não há necessidade de a primeira instância terminar antes que a segunda seja iniciada. Na verdade, é geralmente desejável que ambos sejam executados simultaneamente, de modo que o segundo possa trabalhar com os dados sendo analisados pela primeira vez. Isso é o que acontece aqui, ambos serão chamados sem precisar esperar que o primeiro termine. Isso se aplica a todas as linhas de comandos pipe chains .

I am thinking that the same logic applies to :(){ :|: & };: and

:(){ : & };:

Does the same job as

:(){ :|: & };:

O primeiro não funcionaria, porque apesar de estar sendo executado recursivamente, a função está sendo chamada em segundo plano ( : & ). O primeiro : não espera até que o "filho" : retorne antes de terminar, então, no final, você provavelmente terá apenas uma instância de : em execução. Se você tivesse :(){ : };: , funcionaria, já que o primeiro : aguardaria o retorno do "child" : , o que esperaria que seu próprio "child" : retornasse, e assim por diante. / p>

Veja como os comandos diferentes seriam exibidos em termos de quantas instâncias seriam executadas:

:(){ : & };:

1 instância (chama : e sai) - > 1 instância (chama : e sai) - > 1 instância (chama : e sai) - > 1 instância - > ...

:(){ :|: &};:

1 instância (chama 2 : e sai) - > 2 instâncias (cada um chama 2 : e sai) - > 4 instâncias (cada um chama 2 : e sai) - > 8 instâncias - > ...

:(){ : };:

1 instância (chama : e aguarda a devolução) - > 2 instâncias (filho chama outro : e aguarda a sua devolução) - > 3 instâncias (filho chama outro : e aguarda que ele volte) - > 4 instâncias - > ...

:(){ :|: };:

1 instância (chama 2 : 's e espera que retornem) - > 3 instâncias (as crianças chamam 2 : cada e esperam que voltem) - > 7 instâncias (as crianças chamam 2 : cada e esperam que voltem) - > 15 instâncias - > ...

Como você pode ver, chamar a função em segundo plano (usando & ) retarda a bomba do fork, porque o chamado será encerrado antes que as funções chamadas retornem.

    
por 16.10.2016 / 20:23