Предотвращение MSYS 'bash' от процессов убийства, которые ловят ^C

у меня есть консольное приложение Windows (портированное из Unix), которое изначально было разработано для чистого выхода при получении ^C (Unix SIGINT). Чистый выход в этом случае предполагает ожидание, потенциально довольно долгое время, закрытия удаленных сетевых подключений. (Я знаю, что это не нормальное поведение ^C но я не в состоянии изменить его.) Программа однопоточная.

Я могу поймать ^C С signal(SIGINT) (как в UNIX) или с SetConsoleCtrlHandler. Либо работает правильно, когда программа запускается под CMD.ИСПОЛНЯЕМЫЙ. Однако, если я использую оболочку "bash", которая поставляется с MSYS (я использую среду MinGW для создания программы, так как это позволяет мне повторно использовать файлы Makefile Unix), то программа принудительно завершается некоторое случайное короткое время (менее 100 миллисекунд) после ^C. Это неприемлемо, так как, как я уже упоминал, программа должна ждать удаленной сети соединения для закрытия.

очень вероятно, что люди захотят запустить эту программу под MSYS bash. Кроме того, этот эффект нарушает тестов. Я не смог найти способ обойти проблему ни из программы (идеально), ни по настройкам на оболочке (приемлемо). Кто-нибудь может что-нибудь порекомендовать?

6 ответов


Это может быть связано с печально известным mintty "взаимодействие ввода / вывода с инопланетными программами" (Он же вопрос mintty #56). В этом случае он проявляется в том, что Ctrl-C резко убивает программу, а не передается программе как сигнал, который нужно поймать и обработать. Доказательства этой теории основаны на обширном объяснении zwol: "консольное приложение Windows", " [приложение] предназначено для чистого выхода, когда оно получило ^C", " [приложение] работает правильно, когда программа запускается под CMD.EXE " но " [при использовании терминала], который поставляется с MSYS [...] программа принудительно прекращается " (на момент написания (2018) MSYS по умолчанию использует mintty в качестве своего терминала).

к сожалению mintty не является полной заменой консоли Windows и различные поведения, ожидаемые "родными" программами Windows, не реализованы. Тем не менее, у вас может быть какая-то радость, обернув такой родной программы в winpty при запуске их в mintty...

другие вопросы также описывают это поведение: см. https://superuser.com/questions/606201/how-to-politely-kill-windows-process-from-cygwin и https://superuser.com/questions/1039098/how-to-make-mintty-close-gracefully-on-ctrl-c .


У меня была точно такая же проблема - я написал программу с обработчиком SIGINT/SIGTERM. Этот обработчик делал уборку, которая иногда занимала некоторое время. Когда я запускал программу из msys bash, ctrl - c вызывал запуск моего обработчика SIGINT, но он не заканчивался-программа была завершена ("извне", как это было), прежде чем она могла завершить свою очистку.

основываясь на ответе phs, и этот ответ на аналогичный вопрос: https://stackoverflow.com/a/23678996/2494650, я придумал следующее решение. Это безумно просто, и это может иметь некоторые побочные эффекты, которые я еще не обнаружил, но это исправило проблему для меня.

создайте файл ~/.файл bashrc следующую строку:

trap '' SIGINT

вот и все. Это ловушки сигнала sigint и предотвращает msys bash от завершения вашей программы "извне". Тем не менее, он каким-то образом все еще позволяет сигналу SIGINT до вашего программа, позволяющая ей выполнять изящную очистку / выключение. Я не могу точно сказать, почему это так работает, но это так - по крайней мере для меня.

удачи!


Arg-5 минут редактирования по комментарию. Вот что я хотел написать:--2-->

в качестве обходного пути, вместо того, чтобы пытаться поймать событие CTRL-C, которое также распространяется на оболочку, я бы предложил отключить ENABLED_PROCESSED_INPUT на stdin, чтобы CTRL-C сообщалось как ввод с клавиатуры, а не как сигнал:

DWORD mode;
HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE);
GetConsoleMode(hstdin, &mode);
SetConsoleMode(hstdin, mode & ~ENABLE_PROCESSED_INPUT); /* disable CTRL-C processing as a signal */

затем вы можете обработать ввод клавиатуры в главном потоке, а остальная часть программы делает свое дело в отдельном потоке и установить событие в очистка при получении CTRL-C.


когда вы запускаете свою программу с MSYS bash, вы запускаете исполняемый файл напрямую или есть сценарий оболочки обертывания (bash)?

Если это так, он может регистрировать пользовательский обработчик Ctrl-C с trap command (это делает сон с последующим убийством.) Если такая вещь существует, измените или удалите ее.

Если нет trap registered, или нет сценария обертывания, рассмотрите возможность создания такого сценария и добавления собственной ловушки для переопределения поведения по умолчанию. Вы можете см. пример того, как его использовать здесь или man page Баша (в разделе оболочки BUILTINS).


Ctrl-C-это SIGINT? Я думал, Ctrl-Z-это SIGINT, но Ctrl-C-это SIGTERM. Проверь это.


У вас есть настройка среды CYGWIN (в панели управления/переменных среды)? Попробуйте установить CYGWIN=notty и перезапустить новую оболочку MSYS bash-проблема сохраняется?