c++ - Visual C++ 2015 中的 SIGINT 处理程序重置

标签 c++ signals

考虑以下测试程序

#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";
}

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

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

来验证
auto prev = std::signal(SIGINT, set_signal_raised);
if (prev != set_signal_raised) {
    std::cerr << "Unexpected handler." << std::endl;
    abort();
}

到检查功能。这是允许的和预期的吗?

最佳答案

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

来自signal(2) :

POSIX.1 solved the portability mess by specifying sigaction(2), which provides explicit control of the semantics when a signal handler is invoked; use that interface instead of signal().

In the original UNIX systems, when a handler that was established using signal() was invoked by the delivery of a signal, the disposition of the signal would be reset to SIG_DFL, and the system did not block delivery of further instances of the signal. This is equivalent to calling sigaction(2) with the following flags:

sa.sa_flags = SA_RESETHAND | SA_NODEFER;

System V also provides these semantics for signal(). This was bad because the signal might be delivered again before the handler had a chance to reestablish itself. Furthermore, rapid deliveries of the same signal could result in recursive invocations of the handler.

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

Is this allowed and expected?

这是允许的,但肯定不受欢迎。为此,POSIX推出了sigaction() 。如果您有 sigaction() 则使用它。 否则,您只需要每次在信号处理程序内重新安装处理程序:

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

关于c++ - Visual C++ 2015 中的 SIGINT 处理程序重置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41552081/

相关文章:

c++ - 性能:我应该在经常调用的函数中使用全局变量吗?

c - 如何检测 Linux 上失效的进程?

c++ - 编写一个模板函数来评估具有任何返回类型的 lambda 函数?

C++ template tricky partial specialization const+template 成员

c++ - 在 Qt5 中发送 JSON 文件的 POST 请求

c++ - C/C++ 中的高级指针类型转换

ios - Swift 3 中的 rac_textSignal

django - 传递参数 django 信号 - post_save/pre_save

我们可以重置 sigsetjmp 以再次返回 "0"(重置 sigsetjmp)吗?

signals - Modelsim 和 GHDL 无法将 vhdl 用户定义的信号类型转储到 vcd 中?