考虑以下测试程序
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";
}
检查功能。这是允许的还是预期的?
答案 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;
}