fork () ramifica mais do que o esperado?

186

Considere o seguinte trecho de código:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(void)
{
    int i;
    for(i = 0; i < 2; i++)
    {
        fork();
        printf(".");
    }
    return 0;
}

Este programa gera 8 pontos. Como isso pode ser possível? Não deveria haver 6 pontos?

Nikolay Kovalenko
fonte
14
ideone.com/B9HXL
Antonio Pérez

Respostas:

245

O fork()primitivo geralmente amplia a imaginação. Até você ter uma ideia, você deve rastrear no papel o que é cada operação e explicar o número de processos. Não esqueça que fork () cria uma cópia quase perfeita do processo atual. A diferença mais significativa (para a maioria dos propósitos) é que fork()o valor de retorno difere entre pai e filho. (Como esse código ignora o valor de retorno, não faz diferença.)

Então, a princípio, há um processo. Isso cria um segundo processo, que imprime um ponto e um loop. Na segunda iteração, cada um cria outra cópia, para que haja quatro processos imprimam um ponto e depois saiam. Assim, podemos facilmente contabilizar seis pontos, como você espera.

No entanto, o que printf()realmente faz é armazenar em buffer sua saída. Portanto, o primeiro ponto de quando havia apenas dois processos não aparece quando escrito. Esses pontos permanecem no buffer - que é duplicado na bifurcação (). Não é até que o processo esteja prestes a sair que o ponto em buffer aparece. Quatro processos imprimindo um ponto no buffer, mais o novo fornece 8 pontos.

Se você quiser evitar esse comportamento, ligue para fflush(stdout);depois printf().

Wallyk
fonte
12
Obrigado, eu não sabia que o buffer é duplicado com fork (). Isso explica um comportamento tão estranho.
Nikolay Kovalenko
1
Isso não deveria dar 10 pontos, não 8? Como os filhos da 4ª geração herdam o ponto armazenado em buffer, adicionam seus próprios e, em seguida, liberam na saída, eles imprimem um total de 8 pontos, mas os 2 processos da primeira geração ainda têm um ponto em buffer e os liberam na saída, dando um total de 10.
psusi 21/06/12
12
@psusi Um dos processos de segunda geração é o de primeira geração. fork()não cria 2 e sai, apenas cria mais 1 processo.
precisa saber é o seguinte
70

Você possui buffers não confirmados nos fluxos de saída . stdout é buffer de linha e o buffer é replicado junto com o restante do processo. Quando o programa termina, o buffer não confirmado é gravado duas vezes (uma vez para cada processo). Ambos usando

printf("a\n");

e

printf("a "); fflush(stdout);

não exiba o problema.

No seu primeiro exemplo, você cria quatro processos que possuem cada um dos dois pontos no buffer do fluxo de saída. Quando cada fluxo termina, ele libera seu buffer, gerando oito pontos.

thiton
fonte
2

quando i = 0

Processo_1: texto em buffer = 1 ponto

Processo_2 (criado por Processo_1): texto em buffer = 1 ponto

quando i = 1

Processo_3 (criado por Processo_1): Herda 1 ponto em buffer do Processo_1 e imprime 1 ponto sozinho. No total, Process_3 imprime 2 pontos.

Process_4 (criado por Process_2): Herda 1 ponto em buffer do Process_2 e imprime 1 ponto sozinho. No total, Process_4 imprime 2 pontos.

Processo_1: Imprime 2 pontos (um ponto no buffer quando i = 0 e outro ponto quando i = 1)

Processo_2: Imprime 2 pontos (um ponto no buffer quando i = 0 e outro ponto quando i = 1)

Saída final: 8 pontos. :)

Tauseef
fonte