Após fork (), onde a criança começa sua execução?

22

Estou tentando aprender programação UNIX e me deparei com uma pergunta sobre fork (). Entendo que o fork () cria um processo idêntico ao processo em execução no momento, mas por onde começa? Por exemplo, se eu tiver código

int main (int argc, char **argv)
{
    int retval;
    printf ("This is most definitely the parent process\n");
    fflush (stdout);
    retval = fork ();
    printf ("Which process printed this?\n");

    return (EXIT_SUCCESS);
}

A saída é:

Definitivamente, esse é o processo pai.
Qual processo foi impresso?
Qual processo imprimiu isso?

Eu pensei que isso fork()cria um mesmo processo, então eu inicialmente que naquele programa, a fork()chamada seria recursivamente chamada para sempre. Eu acho que esse novo processo criado a partir do fork()início após a fork()chamada?

Se eu adicionar o código a seguir, para diferenciar um processo pai e filho,

if (child_pid = fork ()) printf ("This is the parent, child pid is %d\n", child_pid);
else printf ("This is the child, pid is %d\n",getpid ());

após a chamada fork (), onde o processo filho inicia sua execução?

Gilles 'SO- parar de ser mau'
fonte
5
man forké certo o suficiente para responder à sua pergunta, btw
alex

Respostas:

23

O novo processo será criado dentro da fork()chamada e começará retornando da mesma forma que o pai. O valor de retorno (no qual você armazenou retval) fork()será:

  • 0 no processo filho
  • O PID do filho no processo pai
  • -1 no pai, se houve uma falha (não há filho, naturalmente)

Seu código de teste funciona corretamente; ele armazena o valor de retorno de fork()in child_pide usa ifpara verificar se é 0 ou não (embora não verifique se há um erro)

Michael Mrozek
fonte
13

Eu pensei que fork () cria o mesmo processo, então, inicialmente, que nesse programa, a chamada fork () seria chamada recursivamente para sempre. Eu acho que o novo processo criado a partir de fork () inicia após a chamada fork ()?

Sim. Vamos numerar as linhas:

int main (int argc, char **argv)
{
    int retval;                                               /* 1 */
    printf ("This is most definitely the parent process\n");  /* 2 */
    fflush (stdout);                                          /* 3 */
    retval = fork ();                                         /* 4 */
    printf ("Which process printed this?\n");                 /* 5 */
    return (EXIT_SUCCESS);                                    /* 6 */
}

O fluxo de execução é:

caller process     fork()  ...
                          
original program            exec()  2  3  4  5  6
                                               
forked program                                   5  6

... o que explica exatamente a saída que você recebeu.

Se você quiser saber como o programa original e bifurcado pode se comportar de maneira diferente, já que eles necessariamente compartilham o mesmo código, consulte a resposta de Michael Mrozek.

badp
fonte
Observe que 1 não é realmente uma instrução. Observe também que os programas originais e bifurcados não são executados ao mesmo tempo - um deles terá que esperar o outro render / ser antecipado.
badp
1
Em sistemas multi-core / multi-CPU, ambos os programas podem realmente ser executados ao mesmo tempo.
Jlliagre
@jilliagre Os sistemas multicore são realmente sobre multithreading. Quanto aos sistemas com várias CPUs, não sei se é esse o caso ou não na prática. Não sou especialista neste campo - e parece um cenário improvável. Se concordarmos que o sistema operacional pode executar vários processos ao mesmo tempo (como ele lidaria com a simultaneidade?), Quando o programa original executar a instrução 4 em uma CPU, as outras CPUs provavelmente estarão ocupadas executando outros processos de qualquer maneira.
badp
Eu diria que é um cenário muito provável, especialmente porque há uma chamada de sistema subjacente com alguma E / S acontecendo na etapa 5. Ter todas as CPUs ocupadas não é realmente uma situação comum, pois a CPU raramente é o gargalo das máquinas atuais. Parece também que você está confundindo multi-threading e multi-core.
Jlliagre #
8
Posso apenas comentar para dizer que essas setas diagonais são fantásticas .
JBirch
0

A verdadeira solução para isso é

switch (fork()) {
    case -1 :
        fprintf (stderr, "fork failed (%s)\n", strerror(errno));
        break;
    case 0 :  // child process comes here
        break;
    default : // parent process
        break;
}

// all continue here
ott--
fonte
-1

qualquer que seja o código logo após o fork(), é copiado no processo filho e não confunda o processo pai e filho, são duas entidades diferentes, que têm o mesmo ambiente (duplicado, não compartilhado).

Agora veja sua saída ...

user2670535
fonte