anomalía de printf después de “fork ()”

2 minutos de lectura

avatar de usuario
pechenie

SO: Linux, Idioma: C puro

Estoy avanzando en el aprendizaje de programación en C en general, y programación en C bajo UNIX en un caso especial.

Detecté un comportamiento extraño (para mí) del printf() función después de usar un fork() llamar.

Código

#include <stdio.h>
#include <system.h>

int main()
{
    int pid;
    printf( "Hello, my pid is %d", getpid() );

    pid = fork();
    if( pid == 0 )
    {
            printf( "\nI was forked! :D" );
            sleep( 3 );
    }
    else
    {
            waitpid( pid, NULL, 0 );
            printf( "\n%d was forked!", pid );
    }
    return 0;
}

Producción

Hello, my pid is 1111
I was forked! :DHello, my pid is 1111
2222 was forked!

¿Por qué apareció la segunda cadena “Hola” en la salida del niño?

Sí, es exactamente lo que imprimió el padre cuando comenzó, con el nombre del padre pid.

¡Pero! Si colocamos un \n carácter al final de cada cadena obtenemos el resultado esperado:

#include <stdio.h>
#include <system.h>

int main()
{
    int pid;
    printf( "Hello, my pid is %d\n", getpid() ); // SIC!!

    pid = fork();
    if( pid == 0 )
    {
            printf( "I was forked! :D" ); // removed the '\n', no matter
            sleep( 3 );
    }
    else
    {
            waitpid( pid, NULL, 0 );
            printf( "\n%d was forked!", pid );
    }
    return 0;
}

Producción:

Hello, my pid is 1111
I was forked! :D
2222 was forked!

¿Por que sucede? ¿Es el comportamiento correcto o es un error?

fork() crea efectivamente una copia del proceso. Si antes de llamar fork(), tenía datos almacenados en búfer, tanto el padre como el hijo tendrán los mismos datos almacenados en búfer. La próxima vez que cada uno de ellos haga algo para vaciar su búfer (como imprimir una nueva línea en el caso de la salida del terminal), verá esa salida almacenada en el búfer además de cualquier nueva salida producida por ese proceso. Entonces, si va a usar stdio tanto en el padre como en el hijo, entonces debería fflush antes de bifurcar, para asegurarse de que no haya datos almacenados en búfer.

A menudo, el niño se utiliza sólo para llamar a un exec* función. Dado que eso reemplaza la imagen completa del proceso secundario (incluidos los búferes), técnicamente no hay necesidad de fflush si eso es realmente todo lo que vas a hacer en el niño. Sin embargo, si puede haber datos almacenados en búfer, debe tener cuidado con la forma en que se maneja una falla de ejecución. En particular, evite imprimir el error en stdout o stderr usando cualquier función stdio (write está bien), y luego llamar _exit (o _Exit) en lugar de llamar exit o simplemente regresando (lo que eliminará cualquier salida almacenada en búfer). O evite el problema por completo enjuagando antes de bifurcar.

  • fflush(stdout); Parece ser la respuesta más correcta aquí, en mi opinión.

    – Oxagast

    29 de septiembre de 2017 a las 6:52


¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad