Почему программа с fork () иногда печатает свой вывод несколько раз?

Существует ряд решений для автоматического монтирования, но я особенно рекомендую те, которые основаны на udev - например, uam .

Кроме того, для обычного пользователя, монтирования из командной строки и по требованию я бы рекомендовал pmount (программы монтирования на основе политик, не требующие sudo ).

51
06.06.2018, 04:50
4 ответа

Cuando se envía a la salida estándar usando la función printf()de la biblioteca C, la salida generalmente se almacena en búfer. El búfer no se vacía hasta que genera una nueva línea, llama fflush(stdout)o sale del programa (no llamando _exit()aunque ). El flujo de salida estándar se almacena de forma predeterminada en la línea -de esta manera cuando está conectado a un TTY.

Cuando bifurca el proceso en el "Programa 2", los procesos secundarios heredan todas las partes del proceso principal, incluido el búfer de salida sin vaciar. Esto copia efectivamente el búfer no vaciado en cada proceso secundario.

Cuando finaliza el proceso, los búferes se vacían. Inicia un gran total de ocho procesos (, incluido el proceso original ), y el búfer no vaciado se vaciará al final de cada proceso individual.

Son ocho porque en cada fork()obtienes el doble de procesos que tenías antes delfork()(ya que son incondicionales ), y tienes tres de estos (2 3 = 8 ).

104
27.01.2020, 19:33

@Kusalananda explicó por qué la salida se repite . Si tiene curiosidad por qué la salida se repite 8 veces y no solo 4 veces (el programa base + 3 bifurcaciones):

int main()
{
    printf("hello world...");
    fork(); // here it creates a copy of itself --> 2 instances
    fork(); // each of the 2 instances creates another copy of itself --> 4 instances
    fork(); // each of the 4 instances creates another copy of itself --> 8 instances
}
12
27.01.2020, 19:33

No afecta a la bifurcación de ninguna manera.

En el primer caso, termina con 8 procesos sin nada que escribir, porque el búfer de salida ya se vació (debido a\n).

En el segundo caso, todavía tiene 8 procesos, cada uno con un búfer que contiene "Hola mundo..." y el búfer se escribe al final del proceso.

19
27.01.2020, 19:33

El trasfondo importante aquí es que stdoutdebe estar en el búfer de línea por el estándar como configuración predeterminada.

Esto hace que \nlimpie la salida.

Dado que el segundo ejemplo no contiene la nueva línea, la salida no se vacía y como fork()copia todo el proceso, también copia el estado del búfer stdout.

Ahora, estas llamadas fork()en su ejemplo crean 8 procesos en total -todos ellos con una copia del estado del búfer stdout.

Por definición, todos estos procesos llaman a exit()cuando regresan de main()y exit()llaman a fflush()seguido de fclose()en todas las transmisiones stdio activas. Esto incluye stdouty, como resultado, ve el mismo contenido ocho veces.

Es una buena práctica llamar a fflush()en todos los flujos con salida pendiente antes de llamar a fork()o dejar que el niño bifurcado llame explícitamente _exit()que solo sale del proceso sin vaciar los flujos de stdio.

Tenga en cuenta que llamar a exec()no vacía los búferes de stdio, por lo que está bien no preocuparse por los búferes de stdio si (después de llamar afork())llama a exec()y (si eso falla )llame al _exit().

Por cierto :Para comprender que el almacenamiento en búfer incorrecto puede causar, aquí hay un error anterior en Linux que se solucionó recientemente:

El estándar requiere que stderresté sin búfer de forma predeterminada, pero Linux ignoró esto e hizo que stderrtuviera un búfer de línea y (aún peor )tuviera un búfer completo en caso de que stderr fuera redirigido a través de una canalización. Entonces, los programas escritos para UNIX generaron cosas sin nueva línea demasiado tarde en Linux.

Vea el comentario a continuación, parece que ahora está solucionado.

Esto es lo que hago para solucionar este problema de Linux:

    /* 
     * Linux comes with a broken libc that makes "stderr" buffered even 
     * though POSIX requires "stderr" to be never "fully buffered". 
     * As a result, we would get garbled output once our fork()d child 
     * calls exit(). We work around the Linux bug by calling fflush() 
     * before fork()ing. 
     */ 
    fflush(stderr); 

Este código no daña en otras plataformas ya que llamar a fflush()en una transmisión que acaba de vaciarse es un noop.

5
27.01.2020, 19:33

Теги

Похожие вопросы