LINUX.ORG.RU

объясните fork

 ,


2

4

Есть простой скрипт fork.py

#!/usr/bin/python

import os

print "start"
if os.fork() == 0:
    print "fork"
print "finish"
yur4@homebox:~ $ ./fork.py 
start
finish
fork
finish

А вот вывод через пайп неожиданный.

yur4@homebox:~ $ ./fork.py |cat
start
finish
start
fork
finish

★★

Любопытно. Вот различия по strace:

1961  write(1, "start\n", 6)
1961  write(1, "finish\n", 7 <unfinished ...>
1962  write(1, "fork\n", 5 <unfinished ...>
1962  write(1, "finish\n", 7)
# случай 2
1970  write(1, "start\nfinish\n", 13)   = 13
1971  write(1, "start\nfork\nfinish\n", 18) = 18

Моя версия: pipe не флашится при переводе строки и после форка получилось два пайпа в каждом из которых осталась строка «start». В пользу этой версии говорит то что если дёрнуть sys.stdout.flush() после первого print то всё будет работать как ожидается.

По-моему, это известный грабли с форком. Попробуй загуглить.

true_admin ★★★★★
()
Ответ на: комментарий от true_admin

Моя версия: pipe не флашится при переводе строки

Все верно. Перед форком нужно делать флаш. Но это не грабли конкретно форка, это грабли буферизации.

mix_mix ★★★★★
()
Последнее исправление: mix_mix (всего исправлений: 1)
Ответ на: комментарий от true_admin

Да, похоже, что что-то с буффером:

#!/usr/bin/python

import os

print os.getpid(), "start"
if os.fork() == 0:
        print os.getpid(), "fork"
else:
        os.wait()
print os.getpid(), "finish"
$ python fork.py | cat
30646 start
30648 fork
30648 finish
30646 start
30646 finish
$ python -u fork.py | cat
30649 start
30651 fork
30651 finish
30649 finish
$ python fork.py 
30655 start
30656 fork
30656 finish
30655 finish

PS: в хороших семьях детей ждут, а не делают их зомби ;)

beastie ★★★★★
()
Ответ на: комментарий от madcore

Век живи, век учись. ;)

Вот, кстати хорошее объяснение на пальцах: http://stackoverflow.com/questions/2530663/printf-anomaly-after-fork

И ещё: http://mdoc.su/o/setvbuf

     The three types of stream buffering available are unbuffered, block
     buffered, and line buffered.  When an output stream is unbuffered,
     information appears on the destination file or terminal as soon as
     written; when it is block buffered, many characters are saved up and
     written as a block; when line buffered, characters are saved up until a
     newline (`\n') is output or input is read from any stream attached to a
     terminal device (typically stdin).

Одним словом — в shell буферизация линейная, в pipe — блочная. Вот и разгадка.

beastie ★★★★★
()
Последнее исправление: beastie (всего исправлений: 1)
Ответ на: комментарий от beastie

Смак в том, что выхлоп может быть рандомный даже на одной системе. Но это излюбленный вопрос hr, типа «что выдаст этот говноскрипт с форками», который(вопрос) в общем-то некорректен.

madcore ★★★★★
()
Ответ на: комментарий от beastie

Думаю разгадка в том, что при форке дочерний процесс получается полной копией родительского, включая буферы, терминалы в/в и т.д.

ziemin ★★
()
Ответ на: комментарий от ziemin

Это то да, это ясно. Но тут цимес в том, что при выводе в шелл stdout флушется по NL и после форка получаестя чистый буффер, а вот при выводе в пайп — по границе блока и тут вот старый контент и остаётся.

beastie ★★★★★
()
Ответ на: комментарий от true_admin

Задачи бывают сложнее «print», в мултипроцессорной конфигурации может быть заранее неизвестно, что быстрее отработает, чем как нагружены ядра, какой планировщик итд итп.

madcore ★★★★★
()

результат данного говнокода не определён. Т.е. как получится. Нужно закрывать файл, прежде чем туда что-то писать, а если два процесса пишут в один файл одновременно, то получается хрень.

тебе нужен

O_ASYNC Enable signal-driven I/O: generate a signal (SIGIO by default, but this can be changed via fcntl(2)) when input or output becomes possible on this file descriptor. This feature is only available for terminals, pseudoterminals, sockets, and (since Linux 2.6) pipes and FIFOs. See fcntl(2) for further details.

тогда будет всё правильно.

emulek
()
Ответ на: комментарий от emulek

Нужно закрывать файл, прежде чем туда что-то писать

Доо, писать в закрытый файл — это последний писк моды.

Уже все разобрались, пришел батек и давай гнать космическую пургу, впрочем just as planned.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.