В вашем случае тупик может возникнуть, когда родительский процесс достигает этой строки:
write(pc[1], theinput.c_str(), theinput.size());
Если «theinput» много данных, то родительский процесс может заполнить канал pc
. Дочерний процесс (cat
здесь) может прочитать часть этого, но не все. cat
Отдадут ли они это вам. Но опять же, если данных много, он может заполнить канал cp
и будет блокироваться, пока кто-то не прочитает данные из этого канала. Это никогда не произойдет, потому что родительский процесс блокируется, ожидая истечения канала pc
, и никогда не достигнет кода, который потребляет содержимое канала cp
. ТУПИК.
Как сказали ваши собеседники в IRC, то, произойдет это или нет, зависит от многих факторов, таких как объем данных, количество данных, которое канал может разместить перед тем, как заблокировать (параметр, зависящий от ядра), количество stdio или другая буферизация, выполняемая родительским или дочерним процессом и т. д. *
Ваши варианты:
Используйте два процесса для управления внешней командой: один, который передает ей данные, и другой, который считывает результаты обратно. Для этого вам придется fork()
дважды. Это очень похоже на конвейер оболочки. Обычно конечным источником данных является процесс внука, фильтром является средний родительский элемент и конечный приемник данных процесса grantparent.
Используйте два потока для управления внешней командой. Аналогично предыдущему варианту.
Используйте неблокирующий ввод / вывод для управления внешней командой. Установите оба дескриптора файла в неблокирующий режим с помощью fcntl()
и настройте цикл обработки событий с помощью poll()
или select()
, чтобы дождаться готовности любого дескриптора файла. Когда любой файловый дескриптор готов, будьте готовы к тому, что write()
завершится только частично, а к read()
не прочитает все сразу.
Используйте существующий цикл событий, такой как glib's , настройте ваши каналы как IO Channels и смотрите их , чтобы знать, когда пора читать или напишите данные. Аналогичен предыдущему параметру, но использует существующую платформу, поэтому вы можете интегрироваться с существующим циклом событий приложения.
Кстати: ваш exit(1)
должен быть _exit(1)
, чтобы не допустить ненадлежащего вызова библиотекой C перехватчиков времени выхода в недолговечном дочернем процессе.