Dopo fork (), da dove inizia l'esecuzione il bambino?


22

Sto cercando di imparare la programmazione UNIX e mi sono imbattuto in una domanda riguardante fork (). Capisco che fork () crea un processo identico al processo attualmente in esecuzione, ma da dove inizia? Ad esempio, se ho il codice

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);
}

L'output è:

Questo è sicuramente il processo genitore
Quale processo ha stampato questo?
Quale processo ha stampato questo?

Ho pensato che fork()crea uno stesso processo, quindi inizialmente quello in quel programma, la fork()chiamata sarebbe stata chiamata in modo ricorsivo per sempre. Immagino che il nuovo processo creato da fork()inizi dopo la fork()chiamata?

Se aggiungo il seguente codice, per distinguere tra un processo padre e figlio,

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 ());

dopo la chiamata fork (), da dove inizia l'esecuzione del processo figlio?


5
man forkè abbastanza sicuro per rispondere alla tua domanda, a proposito
alex

Risposte:


23

Il nuovo processo verrà creato all'interno della fork()chiamata e inizierà ritornando da esso proprio come il genitore. Il valore restituito (da cui è stato archiviato retval) fork()sarà:

  • 0 nel processo figlio
  • Il PID del figlio nel processo padre
  • -1 nel genitore se si è verificato un errore (non esiste un figlio, naturalmente)

Il tuo codice di test funziona correttamente; memorizza il valore restituito da fork()in child_pide lo utilizza ifper verificare se è 0 o meno (anche se non verifica la presenza di un errore)


13

Ho pensato che fork () crea uno stesso processo, quindi inizialmente che in quel programma, la chiamata fork () sarebbe stata chiamata in modo ricorsivo per sempre. Immagino che il nuovo processo creato da fork () inizi dopo la chiamata fork ()?

Sì. Numeriamo le linee:

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 */
}

Il flusso di esecuzione è:

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

... che spiega esattamente l'output ricevuto.

Se vuoi sapere come il programma originale e biforcato può comportarsi in modo diverso, dal momento che condividono necessariamente lo stesso codice, vedi la risposta di Michael Mrozek.


Si noti che 1 non è in realtà un'istruzione. Si noti inoltre che i programmi originali e biforcati in realtà non vengono eseguiti contemporaneamente: uno dei due dovrà attendere che l'altro produca / sia anticipato.
badp,

1
Su sistemi multi-core / multi-cpu, entrambi i programmi possono effettivamente essere eseguiti contemporaneamente.
jlliagre,

@jilliagre I sistemi multicore riguardano davvero il multithreading. Per quanto riguarda i sistemi con più CPU, non so se questo è il caso o meno nella pratica. Non sono un esperto in questo campo - e sembra uno scenario così improbabile. Se siamo d'accordo che il sistema operativo può eseguire più processi contemporaneamente (quindi come gestirà la concorrenza?), Quando il programma originale esegue l'istruzione 4 su una CPU, le altre CPU sono probabilmente occupate ad eseguire altri processi comunque.
badp,

Direi che è uno scenario molto probabile, soprattutto perché c'è una chiamata di sistema sottostante con alcuni I / O che si verificano nel passaggio 5. Avere tutte le CPU occupate in realtà non è una situazione comune poiché la CPU è raramente il collo di bottiglia con le macchine attuali. Sembra anche che tu stia confondendo multi-threading e multi-core.
jlliagre,

8
Posso solo commentare per dire che quelle frecce diagonali sono fantastiche .
JBirch,

0

La vera soluzione a questo è

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

-1

qualunque sia il codice subito dopo fork(), viene copiato nel processo figlio e non confonde il processo padre e figlio, sono due entità diverse, che hanno lo stesso ambiente (duplicato, non condiviso).

Ora guarda il tuo output ...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.