Коллеги, всем привет. Случайно возник вот такой вот архитектурно-философский вопрос.
Сценарий: консольная программа А использует в работе консольную программу Б.
При этом есть два под-сценария:
1. К моменту старта А программа Б уже запущена. Тогда она торчит на каком-то порту 127.0.0.1, программа А подключается туда и делает всё необходимое.
1. К моменту старта А программы Б нет. Тогда А должна сначала запустить Б, и уже потом подключиться.
Нюанс — в том, что после окончания работы А программа Б должна продолжить свою работу ещё какое-то время.
И при этом нам бы хотелось помочь пользователю диагностировать неполадки запуска программы Б.
Сама Б пишет всё, что с ней происходит, в консоль и в лог-файл.
Так что если бы пользователь сам запускал Б, то он бы увидел вывод Б в консоль, и если ей что-то мешает запуститься — там была бы диагностика.
Ок, А в случае если запускает Б, то перехватывает её stout/stderr, и транслирует их пользователю.
И вот мне ИИ на эту тему говорит: постой, но когда А выйдет, а Б останется работать, то попытки Б писать в консоль могут приводить к E_PIPE.
На вопрос "и чо делать", ИИ предлагает перестать читать консоль Б, а вместо этого tail-ить лог-файл Б.
Но юмор в том, что одна из возможных причин неудачи старта Б — отсутствие прав на запись в дефолтный каталог лога
В связи с чем, собственно, вопрос — есть ли кросс-платформенный способ аккуратно отключиться от stdout дочернего процесса?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Каким способом A перехватывает stdout дочернего B ?
Платформенно-специфичным.
На винде, к примеру, у CreateProcess есть специальные параметры для хэндлов stdin, stdout, stderr.
В линуксе используется комбинация из pipe(), fork(), и exec().
PD>ИИ на эту тему высказывается довольно длинно
Там смущает сама формулировка вопроса — она как будто бы уже подразумевает некоторое решение, а не поиск вариантов.
Из того, что я понял в рассуждениях ИИ, дочерний процесс должен как-то отловить момент окончания родительского, и переоткрыть stdout для продолжения работы.
По идее, если у него есть способ узнать, что выход закрыт, то он может просто больше ничего не писать в stdout.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Ок, А в случае если запускает Б, то перехватывает её stout/stderr, и транслирует их пользователю.
Пусть лучше А перенаправляет консоль Б в файл в своём месте для логов.
В этом случае можно будет продолжить исследовать логи Б, даже если А грохнется.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Sinclair, Вы писали:
S>Из того, что я понял в рассуждениях ИИ, дочерний процесс должен как-то отловить момент окончания родительского, и переоткрыть stdout для продолжения работы.
Ну это технически в Windows не так сложно. При запуске чайлда можно передать ему ID родителя(ну хотя бы через командную строку, кстати, отсутствие его в командной строке будет тем самым означать, что что чайлд запущен не этим родителем, а как-то иначе ), а чайлд по нему получит hParentProcess в контексте чайлда и будет в потоке WaitForSingleObject.
Наверняка в Linux есть аналогичное, а может, в нынешней C++ есть и кроссплатформенное решение.
>По идее, если у него есть способ узнать, что выход закрыт, то он может просто больше ничего не писать в stdout.
Может, дождавшись, больше и не писать. Может с помощью freopen на свой stdout перенаправить его куда-то еще.
Здравствуйте, Sinclair, Вы писали:
S>В связи с чем, собственно, вопрос — есть ли кросс-платформенный способ аккуратно отключиться от stdout дочернего процесса?
Нет.
Re[4]: Отмена перехвата консоли дочернего процесса
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Ну это технически в Windows не так сложно. При запуске чайлда можно передать ему ID родителя(ну хотя бы через командную строку, кстати, отсутствие его в командной строке будет тем самым означать, что что чайлд запущен не этим родителем, а как-то иначе ), а чайлд по нему получит hParentProcess в контексте чайлда и будет в потоке WaitForSingleObject.
PD>Наверняка в Linux есть аналогичное, а может, в нынешней C++ есть и кроссплатформенное решение.
Если и есть, то на уровне какого-то очень advanced API. Не проще ли разбираться с проблемой там, где она возникает — если в pipe не получается писать, то как-то разумно на это реагировать?
PD>Может, дождавшись, больше и не писать. Может с помощью freopen на свой stdout перенаправить его куда-то еще.
freopen работает с FILE*, на которую ссылается глобальная переменная stdout. Реально надо переоткрывать handle, а не трогать структуру, на которую ссылается stdout. Например потому, что не все для записи на консоль используют именно stdio.
Re[4]: Отмена перехвата консоли дочернего процесса
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Ну это технически в Windows не так сложно. При запуске чайлда можно передать ему ID родителя(ну хотя бы через командную строку, кстати, отсутствие его в командной строке будет тем самым означать, что что чайлд запущен не этим родителем, а как-то иначе ), а чайлд по нему получит hParentProcess в контексте чайлда и будет в потоке WaitForSingleObject.
А если у нас нет возможности переписать Б?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Отмена перехвата консоли дочернего процесса
Здравствуйте, Marty, Вы писали: M>А почему А надо завершать? Пусть бы работала, чисто висела, ждала Б.
Потому что не дело блокировать пользовательский терминал после того, как задача завершилась. Б вообще может в разумное время не завершиться.
А скриптам, которые могут вызывать А, нужно получать от неё exit code и продолжать выполнение. M>Ну или прокси какой-то С, который будет жить, пока живёт Б
Я об этом думал. Но ведь тогда у нас тот же самый вопрос по отношению к взаимодействия А и С.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[5]: Отмена перехвата консоли дочернего процесса
Здравствуйте, Sinclair, Вы писали:
S>А если у нас нет возможности переписать Б?
Тогда не совсем понятно, чего Вы хотите
>Из того, что я понял в рассуждениях ИИ, дочерний процесс должен как-то отловить момент окончания родительского, и переоткрыть stdout для продолжения работы.
По идее, если у него есть способ узнать, что выход закрыт, то он может просто больше ничего не писать в stdout.
Дочерний процесс должен отловить, но его нельзя переписать, а в текущем его состоянии такого функционала нет.
В Windows в принципе можно ему такой функционал добавить, не переписывая его
Здравствуйте, Pzz, Вы писали:
Pzz>freopen работает с FILE*, на которую ссылается глобальная переменная stdout. Реально надо переоткрывать handle, а не трогать структуру, на которую ссылается stdout. Например потому, что не все для записи на консоль используют именно stdio.
А черт его знает. Если все же используется stdio, то не уверен, что ему будет хорошо, если его хендл перенаправят без его ведома.
Можно поэкспериментировать.
1. fopen на какой-то файл
2. перенаправляем его хендл на другой файл
3. fwrite
и посмотреть, что получится.
With best regards
Pavel Dvorkin
Re[6]: Отмена перехвата консоли дочернего процесса
PD>Тогда не совсем понятно, чего Вы хотите
Хотим запустить Б, помониторить, что он нам пишет в stdout/stderr, и если всё в порядке — "отключиться" от него, чтобы он продолжал себе работать.
PD>По идее, если у него есть способ узнать, что выход закрыт, то он может просто больше ничего не писать в stdout.
Я пока не встречал программ, которые бы как-то разумно себя вели в случае, если запись в stdout заканчивается неудачей. PD>В Линуксе — понятия не имею.
Вот то-то и оно. Но вот вроде рабочий вариант мне уже предложили