防止MSYS'bash'杀死捕获^ C的进程

时间:2011-08-16 21:50:18

标签: c windows portability windows-console

我有一个控制台模式的Windows应用程序(从Unix移植),最初设计用于在收到 ^ C (Unix SIGINT)时执行干净退出。在这种情况下,干净的出口涉及等待,可能相当长的时间,以便关闭远程网络连接。 (我知道这不是 ^ C 的正常行为,但我无法改变它。)程序是单线程的。

我可以使用signal(SIGINT)(在Unix下)或SetConsoleCtrlHandler来捕获 ^ C 。当程序在CMD.EXE下运行时,可以正常工作。但是,如果我使用MSYS附带的“bash”shell(我使用MinGW环境来构建程序,因为这允许我重用Unix makefile),那么程序会被强制终止一些随机,短时间(小于 ^ C 之后的100毫秒)。这是不可接受的,因为正如我所提到的,程序需要等待远程网络连接关闭。

人们很可能想在MSYS bash下运行这个程序。此外,这种效果打破了测试套件。我无法找到任何方法来解决问题,无论是从程序内(理想)还是通过shell上的设置(可接受)。任何人都可以推荐任何东西吗?

6 个答案:

答案 0 :(得分:7)

我遇到了完全相同的问题 - 我用SIGINT / SIGTERM处理程序编写了一个程序。该处理程序进行了清理工作,有时需要一段时间。当我从msys bash中运行程序时,ctrl-c将导致我的SIGINT处理程序触发,但它无法完成 - 程序在完成清理之前终止(“从外部”,因为它)工作

基于phs的答案,以及对类似问题的回答:https://stackoverflow.com/a/23678996/2494650,我提出了以下解决方案。它非常简单,它可能有一些我尚未发现的副作用,但它解决了我的问题。

使用以下行创建〜/ .bashrc文件:

trap '' SIGINT

就是这样。这会捕获sigint信号并阻止msys bash“从外部”终止你的程序。但是,它仍以某种方式让SIGINT信号通过你的程序,允许它进行优雅的清理/关闭。我不能确切地告诉你它为什么会这样运作,但确实如此 - 至少对我而言。

祝你好运!

答案 1 :(得分:1)

Arg - 对评论进行5分钟编辑。这是我想写的:

作为一种解决方法,不是试图捕获也传播到shell的CTRL-C事件,而是建议关闭stdin上的ENABLED_PROCESSED_INPUT,以便将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时将事件设置为清理。

答案 2 :(得分:1)

这可能是由于臭名昭著的mintty "Input/Output interaction with alien programs"问题(又名mintty issue #56)引起的。在这种情况下,它表现为Ctrl-C突然杀死程序,而不是作为要捕获和处理的信号传递给程序。该理论的证据基于zwol的广泛解释:“控制台模式Windows应用程序”,“ [应用程序被设计为在收到 ^ C 时进行干净退出”,“ [[应用程序]正常工作当程序在CMD.EXE下运行时”,但“ [[在使用终端时]随MSYS程序一起被强制终止”(在撰写本文时(2018年),MSYS默认使用mintty作为其终端)

不幸的是,mintty isn't a full Windows console replacement并没有实现“本机” Windows程序预期的各种行为。但是,在薄荷中运行此类本机程序时,将它们包装在winpty中可能会带来一些乐趣...

其他问题也描述了此行为:请参见https://superuser.com/questions/606201/how-to-politely-kill-windows-process-from-cygwinhttps://superuser.com/questions/1039098/how-to-make-mintty-close-gracefully-on-ctrl-c

答案 3 :(得分:0)

使用MSYS bash运行程序时,是直接运行可执行文件,还是有包装(bash)shell脚本?

如果是这样,它可能正在使用trap命令注册自定义Ctrl-C处理程序(执行睡眠后执行kill)。如果存在这样的情况,请更改或删除它。

如果没有注册trap,或者没有包装脚本,请考虑制作这样的脚本并添加自己的陷阱来覆盖默认行为。您可以查看如何使用它herebash's man page(在SHELL BUILTINS部分中)的示例。

答案 4 :(得分:0)

Ctrl-C是SIGINT?我认为Ctrl-Z是SIGINT,但Ctrl-C是SIGTERM。检查一下。

答案 5 :(得分:0)

您是否有CYGWIN环境设置(在控制面板/环境变量中)?尝试设置CYGWIN = notty并重新打开一个新的MSYS bash shell - 问题是否仍然存在?