2012-06-21 16 views
182

Considere el siguiente fragmento de código:fork() ramas más de lo esperado?

#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 de salidas 8 puntos. ¿Cómo puede ser eso posible? ¿No debería haber 6 puntos en su lugar?

+0

[Ver esta publicación] (http://stackoverflow.com/questions/10909011/how-to-use-fork-to-create-only-2-child-processes/10909090#10909090) – tuxuday

+14

http: //ideone.com/B9HXL –

Respuesta

241

La primitiva fork() a menudo estira la imaginación. Hasta que lo sienta, debe rastrear en el papel qué es cada operación y tener en cuenta el número de procesos. No olvide que fork() crea una copia casi perfecta del proceso actual. La diferencia más significativa (para la mayoría de los propósitos) es que el valor de retorno de fork() difiere entre padre e hijo. (Dado que este código ignora el valor de retorno, no hace ninguna diferencia.)

Por lo tanto, al principio, hay un proceso. Eso crea un segundo proceso, ambos imprimen un punto y un bucle. En su segunda iteración, cada uno crea otra copia, por lo que hay cuatro procesos que imprimen un punto y luego salen. Por lo tanto, podemos contabilizar fácilmente seis puntos, como usted espera.

Sin embargo, lo que printf() realmente hace es amortiguar su salida. Entonces, el primer punto de cuando solo había dos procesos no aparece cuando está escrito. Esos puntos permanecen en el buffer — que se duplica en fork(). No es hasta que el proceso está por salir que aparece el punto amortiguado. Cuatro procesos imprimen un punto amortiguado, más el nuevo da 8 puntos.

Si desea evitar ese comportamiento, llame al fflush(stdout); después de printf().

+12

Gracias, no sabía que el búfer se duplica con fork(). Explica un comportamiento tan extraño. –

+1

¿No debería dar 10 puntos, no 8? Dado que los niños de 4 segunda generación heredan el punto amortiguado, agregan el suyo propio y luego limpian al salir, imprimirían un total de 8 puntos, pero los 2 procesos de la primera generación todavía tendrían un punto cada uno almacenado en el buffer, y enjuagarlos al salir, dando un total de 10. – psusi

+12

@psusi Uno de los procesos de segunda generación _es_ un proceso de primera generación. 'fork()' no crea 2 y luego sale, solo crea 1 proceso más. – Izkata

70

Tiene búferes no confirmados en las secuencias de salida. stdout es buffer de línea, y el buffer se replica junto con el resto del proceso. Cuando el programa finaliza, el buffer no asignado se escribe dos veces (una para cada proceso). Tanto el uso de

printf("a\n"); 

y

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

no presentan el problema.

En su primer ejemplo, crea cuatro procesos que tienen cada dos puntos en su buffer de flujo de salida. Cuando cada flujo termina, vacía su memoria intermedia, generando ocho puntos.

2

cuando i = 0

Process_1: texto Buffered = 1 punto

Process_2 (creado por Process_1): Buffered text = 1 punto

cuando i = 1

Process_3 (creado por Process_1): hereda 1 punto amortiguado de Process_1 e imprime 1 punto por sí mismo. En total Process_3 imprime 2 puntos.

Proceso_4 (creado por Process_2): Hereda 1 punto amortiguado de Process_2 e imprime 1 punto por sí mismo. En total Process_4 imprime 2 puntos.

Process_1: Prints 2 puntos (un punto tamponada cuando i = 0 y otro punto cuando i = 1)

Process_2: Prints 2 puntos (One almacenan temporalmente dot cuando i = 0 y otro punto cuando i = 1)

Salida final: 8 puntos. :)