我有一个控制台模式的Windows应用程序(从Unix移植),最初设计用于在收到 ^ C (Unix SIGINT
)时执行干净退出。在这种情况下,干净的出口涉及等待,可能相当长的时间,以便关闭远程网络连接。 (我知道这不是 ^ C 的正常行为,但我无法改变它。)程序是单线程的。
我可以使用signal(SIGINT)
(在Unix下)或SetConsoleCtrlHandler
来捕获 ^ C 。当程序在CMD.EXE下运行时,可以正常工作。但是,如果我使用MSYS附带的“bash”shell(我使用MinGW环境来构建程序,因为这允许我重用Unix makefile),那么程序会被强制终止一些随机,短时间(小于 ^ C 之后的100毫秒)。这是不可接受的,因为正如我所提到的,程序需要等待远程网络连接关闭。
人们很可能想在MSYS bash下运行这个程序。此外,这种效果打破了测试套件。我无法找到任何方法来解决问题,无论是从程序内(理想)还是通过shell上的设置(可接受)。任何人都可以推荐任何东西吗?
答案 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-cygwin和https://superuser.com/questions/1039098/how-to-make-mintty-close-gracefully-on-ctrl-c。
答案 3 :(得分:0)
使用MSYS bash运行程序时,是直接运行可执行文件,还是有包装(bash)shell脚本?
如果是这样,它可能正在使用trap
命令注册自定义Ctrl-C处理程序(执行睡眠后执行kill)。如果存在这样的情况,请更改或删除它。
如果没有注册trap
,或者没有包装脚本,请考虑制作这样的脚本并添加自己的陷阱来覆盖默认行为。您可以查看如何使用它here或bash's man page(在SHELL BUILTINS部分中)的示例。
答案 4 :(得分:0)
Ctrl-C是SIGINT?我认为Ctrl-Z是SIGINT,但Ctrl-C是SIGTERM。检查一下。
答案 5 :(得分:0)
您是否有CYGWIN环境设置(在控制面板/环境变量中)?尝试设置CYGWIN = notty并重新打开一个新的MSYS bash shell - 问题是否仍然存在?