поведение fork () в linux - PullRequest
       1

поведение fork () в linux

6 голосов
/ 24 ноября 2011

Я пытался понять вилки, и попытался в C:

#include<stdio.h>
#include <unistd.h>

void forker()
{
    printf("%d: A\n",(int)getpid());
    fork();
    wait();
    printf("%d: B\n",(int)getpid());
    printf("%d: C\n",(int)getpid());
    fork();
    wait();
    printf("%d: D\n",(int)getpid());
}

int main(void)
{
    forker();
    return 0;
}

Когда я скомпилировал и запустил результирующий a.out, вот что я заметил:

> ./a.out
3560: A
3561: B
3561: C
3562: D
3561: D
3560: B
3560: C
3563: D
3560: D

Однако, когда я делаю следующее:

> ./a.out > t.txt

происходит что-то странное:

> cat t.txt
3564: A
3565: B
3565: C
3566: D
3564: A
3565: B
3565: C
3565: D
3564: A
3564: B
3564: C
3567: D
3564: A
3564: B
3564: C
3564: D

Может кто-нибудь объяснить, пожалуйста, такое поведение?Почему выходные данные отличаются, когда они перенаправляются в файл?

Я использую Ubuntu 10.10, gcc версии 4.4.5.

Ответы [ 3 ]

10 голосов
/ 24 ноября 2011

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

3 голосов
/ 24 ноября 2011

Проблема в том, что вывод printf передается через буфер библиотеки перед отправкой в ​​файл, что вызывает странное поведение, о котором вы упоминали. Если вы добавите fflush(stdout) после каждого printf, ваш вывод будет правильным и внутри файла.

Подробнее об этом можно прочитать здесь: http://www.pixelbeat.org/programming/stdio_buffering/

2 голосов
/ 24 ноября 2011

Другие ответы точно не описывают происходящее, и мне пришлось немного подумать, чтобы понять. Итак, во втором случае (выходные данные буферизуются из-за перенаправления файлов) и с использованием 1,2,3 и 4 вместо 3564, 3565, 3566 и 3567:

  • процесс 1 печатает «A: 1» во внутреннем буфере стандартного вывода;
  • процесс 1 разветвляется и процесс 2 создается, это создание подразумевает копию внутреннего буфера стандартного вывода, который еще не распечатан;
  • процесс 1 печатает «B: 1» и «C: 1» в своем внутреннем буфере стандартного вывода, процесс 2 «B: 2» и «C: 2»;
  • оба процесса разветвляются (в вашем случае 1-> 4 и 2-> 3, но они могли бы отличаться), дублируя оба внутренних буфера;
  • Все 4 процесса выводят строку D в свои буферы, затем завершают работу.

На данный момент содержимое 4 внутренних буферов стандартного вывода:

- process 1:
    A:1
    B:1
    C:1
    D:1
- process 2:
    A:1
    B:2
    C:2
    D:2
- process 3:
    A:1
    B:2
    C:2
    D:3
- process 4:
    A:1
    B:1
    C:1
    D:4
  • Наконец, 4 буфера печатаются в недетерминированном порядке. В вашем случае заказ был 3, 2, 4, 1.

Такое поведение не происходит, когда stdout является оболочкой или с fflush(), потому что буфер stdout сбрасывается перед каждым fork(), поэтому дублируются только пустые буферы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...