Кто работает первым в форке, с противоречивыми результатами - PullRequest
0 голосов
/ 03 декабря 2018

У меня есть этот простой тест:

int main() {
    int res = fork();
    if (res == 0) { // child
        printf("Son running now, pid = %d\n", getpid());
    }
    else { // parent
        printf("Parent running now, pid = %d\n", getpid());
        wait(NULL);
    }
    return 0;
}

Когда я запускаю его сто раз, т.е. запускаю эту команду,

for ((i=0;i<100;i++)); do echo ${i}:; ./test; done

Я получаю:

0:
Parent running now, pid = 1775
Son running now, pid = 1776
1:
Parent running now, pid = 1777
Son running now, pid = 1778
2:
Parent running now, pid = 1779
Son running now, pid = 1780

и т. Д .;тогда как, когда я сначала записываю в файл и затем читаю файл, т.е. запускаю эту команду,

for ((i=0;i<100;i++)); do echo ${i}:; ./test; done > forout
cat forout

я получаю его перевёрнутым!То есть

0:
Son running now, pid = 1776
Parent running now, pid = 1775
1:
Son running now, pid = 1778
Parent running now, pid = 1777
2:
Son running now, pid = 1780
Parent running now, pid = 1779

Я знаю о планировщике.Что не означает этот результат с точки зрения того, кто бежит первым после разветвления?Функция разветвления, do_fork()kernel/fork.c) заканчивается установкой флага need_resched в 1 с комментарием разработчиков ядра, который говорит: «Пусть дочерний процесс запускается первым».

Я догадался, чтоэто как-то связано с буферами, в которые printf пишет.

Также верно ли, что перенаправление ввода (>) сначала записывает все в буфер, а только потом копирует в файл?И даже в этом случае, почему это изменит порядок печати?

Примечание: Я запускаю тест на одноядерной виртуальной машине с ядром Linux v2.4.14 .

Спасибо за ваше время.

1 Ответ

0 голосов
/ 03 декабря 2018

Когда вы перенаправляете, glibc обнаруживает, что stdout не tty включает буферизацию вывода для эффективности.Поэтому буфер не записывается, пока не завершится процесс.Вы можете увидеть это, например:

int main() {
  printf("hello world\n");
  sleep(60);
}

Когда вы запустите его в интерактивном режиме, он напечатает «Hello World» и ждет.При перенаправлении в файл вы увидите, что в течение 60 секунд ничего не пишется:

$ ./foo > file & tail -f file
(no output for 60 seconds)

Поскольку ваш родительский процесс ожидает дочернего элемента, он всегда будет выходить последним и, следовательно, сбрасывать свой вывод последним.

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