Этот ответ дополняет ответ Мартина Питерса. Ссылки на источники, описывающие режимы буферизации потоков по умолчанию, приведены в конце.
Решения
Вот три основных решения с объяснением:
a) Очищать буферы перед вызовом подпроцесса. Этот вариант может быть значительно более эффективным, когда вы выполняете много вывода из основной программы и всего несколько вызовов подпроцесса.
printf("1. output from printf()\n");
fflush(stdout);
system("echo '2. output from a command called using system()'");
б) Изменить буферизацию stdout на линейную буферизацию (или небуферизацию) для всей программы. Эта опция представляет собой небольшое изменение в программе, так как вы вызываете sevbuf()
только в начале и остальная часть программы остается прежней.
if(setvbuf(stdin, NULL, _IOLBF, BUFSIZ))
err(EXIT_FAILURE, NULL);
printf("1. output from printf()\n");
system("echo '2. output from a command called using system()'");
Изменить:
c) Изменить буферизацию stdout на линейную буферизацию (или небуферизацию) для всей программы с помощью внешней утилиты . Эта опция никак не меняет программу, поэтому вам не нужно перекомпилировать или даже иметь исходники программы. Вы просто вызываете программу с помощью утилиты stdbuf
.
$ stdbuf -oL ./iobuffer | cat
1. output from printf()
2. output from a command called using system()
Ссылки — описание причин изменения режима буферизации.
Начальная настройка буферизации описана, например, в документах ниже. Потоки на интерактивные устройства, такие как терминал, по умолчанию буферизуются строками, поэтому сообщения, заканчивающиеся новой строкой, немедленно появляются на терминале. Каналы, файлы и т. д. используют блочную буферизацию (или полную буферизацию) для повышения производительности.
Справочное руководство по библиотеке GNU C
http://www.gnu.org/software/libc/manual/html_node/Buffering-Concepts.html#Buffering-Concepts
Недавно открытые потоки обычно полностью буферизуются, за одним исключением: поток, подключенный к интерактивному устройству, такому как терминал, изначально буферизуется строкой.
Справочные страницы Linux: стандартный ввод (3)
http://linux.die.net/man/3/stdin
Поток stderr не буферизован. Поток stdout буферизуется строкой, когда он указывает на терминал. Частичные строки не будут отображаться до тех пор, пока не будут вызваны fflush(3) или exit(3), или пока не будет напечатана новая строка. Это может привести к неожиданным результатам, особенно при выводе отладочной информации. Режим буферизации стандартных потоков (или любого другого потока) можно изменить с помощью вызова setbuf(3) или setvbuf(3).
Также упоминается буферизация драйвера терминала.
Проект комитета C11 ISO/IEC 9899:201x — 12 апреля 2011 г.; 7.21.3 Файлы, стр. 301
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
В исходном состоянии стандартный поток ошибок не полностью буферизован; стандартный входной и стандартный выходные потоки полностью буферизуются тогда и только тогда, когда можно определить, что поток не относится к интерактивному устройству.
Открытая группа: системные интерфейсы и заголовки, выпуск 4, версия 2; 2.4 Стандартные потоки ввода-вывода, стр. 32
https://www2.opengroup.org/ogsys/catalog/C435 (для загрузки необходима бесплатная регистрация)
При открытии стандартный поток ошибок буферизуется не полностью; стандартный входной и стандартный выходные потоки полностью буферизуются тогда и только тогда, когда можно определить, что поток не относится к интерактивному устройству.
Также есть очень интересная глава 2.4.1 "Взаимодействие файловых дескрипторов и стандартных потоков ввода-вывода" о комбинировании буферизованного и небуферизованного ввода-вывода, которая в некоторой степени относится к вызовам подпроцессов.
person
pabouk
schedule
04.07.2013