Дублированный вывод с использованием printf () и fork () в C - PullRequest
5 голосов
/ 22 января 2020

Я запускаю эту маленькую программу для проверки fork(), и я не могу понять вывод, код программы:

#include <stdio.h> 
#include <sys/types.h> 
#include <unistd.h> 

int i = 0;
void create()
{
    fork();
    printf("Inside i= %d \n", i);
    i = i + 1;
    fork();
}
int main()
{
    create();  
    return 0;
}

Вывод:

Inside i= 0 
Inside i= 0 
Inside i= 0 
Inside i= 0 

Разве не должно быть только двух выходов, потому что в последнем fork() потомкам нечего распечатывать?

Я читал, что дочерний процесс выполнит следующую инструкцию после fork(), хотя последние дети, кажется, выполнили инструкцию printf().

1 Ответ

13 голосов
/ 22 января 2020

Вывод вашей программы сильно зависит от реализации.

Стандартная библиотека C применяет буферизацию к выходному потоку. Это означает, что он накапливает символы для записи до тех пор, пока буфер не достигнет определенной длины (или пока не будет выполнено определенное условие), а затем выводит весь текст сразу.

Наиболее распространенным поведением является использование буферизация строки , что означает, что текст будет распечатан при обнаружении символа новой строки (\n). Это действительно то, что происходит на моей машине с вашим примером. Поскольку вы fork() до printf(), два процесса выполняют вызов, и выходные данные сразу же выводятся на печать, так как есть новая строка:

$ ./prog
Inside i= 0
Inside i= 0

Другой fork() затем выполняется на каждом из двух процессов, но больше ничего не нужно выводить на печать, поскольку внутренний буфер вывода уже очищен, поэтому в этом случае ничего не происходит.

Однако, в зависимости от вашей конкретной реализации c и условий, в которых программа запущена, printf() (и вообще любая функция stdio) может решить применить другие правила буферизации.

Например, при передаче вывода в другую программу или в файл, glib c обычно использует буфер фиксированного размера и не выполняет буферизацию строки. Поскольку буфер не заполнен одним коротким printf(), текст сохраняется внутри него для последующей печати. Когда вы fork() второй раз, каждый из новых потомков получает копию указанного буфера, и весь текст затем печатается (каждым из них), когда процесс завершается. В моей системе при выводе по конвейеру это вывод:

$ ./prog | cat
Inside i= 0
Inside i= 0
Inside i= 0
Inside i= 0

Если вы хотите убедиться, что текст печатается сразу, вы можете использовать fflush() или отключить буферизацию stdout с setvbuf().

Примеры:

  • Использование fflush():

    void create()
    {
        fork();
        printf("Inside i= %d \n", i);
        fflush(stdout);
        i = i + 1;
        fork();
    }
    
  • Использование setvbuf():

    int main()
    {
        setvbuf(stdout, NULL, _IONBF, 0);
        create();  
        return 0;
    }
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...