在Visual C ++ 2015中重置SIGINT处理程序

时间:2017-01-09 16:08:01

标签: c++ signals

考虑以下测试程序

holidays

使用GCC和Clang,输出“OK”。但是,使用Visual Studio 2015,它不会输出任何内容。

处理完第一个信号后,信号处理程序被重置。这可以通过添加

来验证
#include <csignal>
#include <iostream>

volatile std::sig_atomic_t signal_raised = 0;

void set_signal_raised(int signal) {
    signal_raised = 1;
}

void check(std::sig_atomic_t expected) {
    if (signal_raised != expected) {
        std::cerr << signal_raised << " != " << expected << std::endl;
        abort();
    }
}

int main() {
    using namespace std;
    check(0);
    std::signal(SIGINT, set_signal_raised);
    check(0);
    std::raise(SIGINT);
    check(1);
    signal_raised = 0;
    check(0);
    std::raise(SIGINT);
    check(1);
    cerr << "OK.\n";
}

检查功能。这是允许的还是预期的?

1 个答案:

答案 0 :(得分:1)

重置信号处理是Unix System V使用的行为。但BSD(目前为glibc)不会重置信号处理。允许的POSIX标准允许这两种行为。 C标准没有规定&#34;重置&#34;是允许的。

来自signal(2)

  

POSIX.1通过指定sigaction(2)解决了可移植性问题          在信号处理程序时提供语义的显式控制          调用;使用该接口而不是signal()。

     

在原始UNIX系统中,当已建立的处理程序时          使用signal()是通过传递信号来调用的          信号的处置将重置为SIG_DFL和系统          没有阻止信号的进一步发送。这是          相当于使用以下标志调用sigaction(2):

     

sa.sa_flags = SA_RESETHAND | SA_NODEFER;

     

System V还为signal()提供了这些语义。这很糟糕          因为信号可能会在处理程序有一个之前再次传递          有机会重新建立自己。此外,快速交付          相同的信号可能导致处理程序的递归调用。

因此,Visual Studio似乎遵循System V行为。

  

这是允许的还是预期的?

它被允许但肯定不被期望。出于这个原因,POSIX引入了sigaction()。如果您有sigaction(),请使用它。 否则,您只需要在信号处理程序中每次都重新安装处理程序:

void set_signal_raised(int signal) {
    std::signal(SIGINT, set_signal_raised);
    signal_raised = 1;
}