Después de fork (), ¿dónde comienza el niño su ejecución?

22

Estoy tratando de aprender programación UNIX y encontré una pregunta con respecto a fork (). Entiendo que fork () crea un proceso idéntico al proceso actualmente en ejecución, pero ¿dónde comienza? Por ejemplo, si tengo 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);
}

El resultado es:

Este es definitivamente el proceso principal
¿Qué proceso imprimió esto?
¿Qué proceso imprimió esto?

Pensé que eso fork()crea un mismo proceso, así que inicialmente que en ese programa, la fork()llamada se llamaría recursivamente para siempre. ¿Supongo que el nuevo proceso creado desde fork()comienza después de la fork()llamada?

Si agrego el siguiente código, para diferenciar entre un proceso primario y secundario,

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

después de la llamada fork (), ¿dónde comienza su ejecución el proceso hijo?

Gilles 'SO- deja de ser malvado'
fuente
55
man forkes suficiente para responder a su pregunta, por cierto
alex

Respuestas:

23

El nuevo proceso se creará dentro de la fork()llamada, y comenzará regresando al igual que el padre. El valor de retorno (desde el que almacenó retval) fork()será:

  • 0 en el proceso hijo
  • El PID del niño en el proceso padre
  • -1 en el padre si hubo un fallo (no hay hijo, naturalmente)

Su código de prueba funciona correctamente; almacena el valor de retorno desde fork()adentro child_pidy lo usa ifpara verificar si es 0 o no (aunque no busca un error)

Michael Mrozek
fuente
13

Pensé que fork () crea un mismo proceso, así que inicialmente que en ese programa, la llamada fork () se llamaría recursivamente para siempre. ¿Supongo que el nuevo proceso creado desde fork () comienza después de la llamada fork ()?

Sí. Numeremos las líneas:

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

El flujo de ejecución es:

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

... que explica exactamente la salida que recibió.

Si desea saber cómo el programa original y el bifurcado pueden comportarse de manera diferente, ya que necesariamente comparten el mismo código, vea la respuesta de Michael Mrozek.

badp
fuente
Tenga en cuenta que 1 no es en realidad una instrucción. También tenga en cuenta que los programas originales y bifurcados en realidad no se ejecutan al mismo tiempo: uno de los dos tendrá que esperar a que el otro ceda / sea reemplazado.
badp
1
En sistemas multi-core / multi-cpu, ambos programas pueden ejecutarse al mismo tiempo.
jlliagre
@jilliagre Los sistemas multinúcleo realmente se tratan de subprocesos múltiples. En cuanto a los sistemas con múltiples CPU, no sé si ese es el caso o no en la práctica. No soy un experto en este campo, y parece un escenario tan improbable. Si aceptamos que el sistema operativo puede ejecutar múltiples procesos al mismo tiempo (¿cómo manejaría la concurrencia?), Para cuando el programa original ejecute la instrucción 4 en una CPU, es probable que las otras CPU estén ocupadas ejecutando otros procesos de todos modos.
badp
Diría que es un escenario muy probable, especialmente porque hay una llamada al sistema subyacente con algunas E / S en el paso 5. Tener todas las CPU ocupadas en realidad no es una situación común ya que la CPU rara vez es el cuello de botella con las máquinas actuales. Parece que también estás confundiendo multi-threading y multi-core.
jlliagre
8
¿Puedo comentar para decir que esas flechas diagonales son fantásticas ?
JBirch
0

La verdadera solución a esto es

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--
fuente
-1

cualquiera que sea el código justo después del fork(), se copia en el proceso secundario, y no mezcle el proceso primario y secundario, son dos entidades diferentes, que tienen el mismo entorno (duplicado, no compartido).

Ahora vea su salida ...

usuario2670535
fuente