33

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

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

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

4

6 回答 6

8

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

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

使用以下行创建一个 ~/.bashrc 文件:

trap '' SIGINT

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

祝你好运!

于 2015-08-12T20:41:13.350 回答
2

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

Unfortunately mintty isn't a full Windows console replacement and various behaviours expected by "native" Windows programs are not implemented. However, you might have some joy wrapping such native programs in winpty when running them within mintty...

Other questions also describe this behaviour: see https://superuser.com/questions/606201/how-to-politely-kill-windows-process-from-cygwin and https://superuser.com/questions/1039098/how-to-make-mintty-close-gracefully-on-ctrl-c .

于 2018-10-05T03:13:12.920 回答
1

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

作为一种解决方法,我建议关闭标准输入上的 ENABLED_PROCESSED_INPUT 以便将 CTRL-C 报告为键盘输入而不是信号,而不是尝试捕获也传播到 shell 的 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 时设置一个事件进行清理。

于 2011-09-07T09:01:37.410 回答
0

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

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

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

于 2011-09-04T21:28:19.017 回答
0

Ctrl-C 是 SIGINT?我以为 Ctrl-Z 是 SIGINT,但 Ctrl-C 是 SIGTERM。检查那个。

于 2011-09-05T20:52:26.310 回答
0

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

于 2011-09-06T19:20:21.407 回答