【问题标题】:Why the second SIGINT can't be captured on win32?为什么在win32上无法捕获第二个SIGINT?
【发布时间】:2017-05-14 01:22:42
【问题描述】:

下面是我在 win32 上运行的代码。

#include "stdafx.h"

#include <signal.h>

void  INThandler( int sig )
{
    printf( "Ctrl-C pressed\n" );
}

int main ()
{

   signal( SIGINT, INThandler );
   while (1)
   {
   }

   return 0;
}

我按两次ctrl-c后程序的输出如下。

在 test.exe 中的 0x76707577 (kernel32.dll) 处引发异常:0x40010005: Control-C。

线程 0x6a8 已退出,代码为 0 (0x0)。

在 test.exe 中的 0x76707577 (kernel32.dll) 处引发异常:0x40010005: Control-C。

线程 0x4104 已退出,代码为 -1073741510 (0xc000013a)。

程序“[14580] test.exe”已退出,代码为 -1073741510 (0xc000013a)。

我的问题是:为什么我的第二个 ctrl-c 不能被我的信号处理功能捕获?此类问题应该如何处理?

我遇到了这个问题,因为我的真实程序需要大量资源,并且需要很长时间才能释放这些资源。所以如果在第 2 次 ctrl-c 来临时没有完成释放过程,就会产生一些错误(内存泄漏)。我想避免这种情况。

【问题讨论】:

    标签: winapi sigint


    【解决方案1】:

    来自signal 的文档:

    在执行指定函数之前,func的值被设置为SIG_DFL。下一个中断信号按照 SIG_DFL 的描述处理,除非对信号的中间调用另有说明。

    如果您想捕获同一信号的第二个实例,您需要在信号处理程序中再次调用signal。如果在非常繁忙的系统上以足够近的距离接收到两个中断,这确实会引入潜在的竞争条件。如果您对此感到担忧,您可能更愿意使用原生的SetConsoleCtrlHandler 函数。

    您还应该注意:

    任何 Win32 应用程序都不支持 SIGINT。当发生 CTRL+C 中断时,Win32 操作系统会生成一个新线程来专门处理该中断。这可能会导致单线程应用程序(例如 UNIX 中的应用程序)变为多线程并导致意外行为。

    尽管如此,实际上使用signal 捕获 Control-C 是安全的,前提是您考虑到信号处理程序是从单独的线程调用的事实。但是,如果您希望您的程序严格兼容 Windows,则应使用本机功能。

    【讨论】:

    • 感谢您的快速回复。如果我想让我的代码在 win32 和 linux 上运行,你能提供更多建议吗?
    • 据我所知,没有什么能阻止您在 Linux 的信号处理程序中调用 signal。所以这将适用于两个操作系统。
    • 如果我想捕获相同信号的第二个实例,是否需要在 linux 上的信号处理程序中再次调用信号?
    • 显然这取决于编译器设置,但据我所知,通常没有必要。但是,这并不意味着您不能这样做,我没有看到任何迹象表明它会造成任何伤害。
    【解决方案2】:

    我认为问题在于:

    来自MSDN

    任何 Win32 应用程序都不支持 SIGINT。当发生 CTRL+C 中断时,Win32 操作系统会生成一个新线程以 专门处理该中断。这可能会导致单线程 应用程序(例如 UNIX 中的应用程序)变为多线程并导致 意外行为。


    所以,您可以更改为其他信号而不是SIGINT

    【讨论】:

    • 由于 OP 想要处理用户按下 Control-C 的情况,因此使用不同的信号是不切实际的。此外,SIGINT 是 Windows 上唯一可以在外部生成的信号,其他所有信号都只能从进程内部引发。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-30
    • 2018-12-12
    • 1970-01-01
    • 1970-01-01
    • 2016-01-04
    • 2018-03-14
    • 2016-04-05
    相关资源
    最近更新 更多