use*_*645 0 c++ signals polling
信号SIGTERM和SIGINT的信号处理程序在接收到任何一个信号时会导致轮询错误.我不确定为什么会这样做,我想我不知道我错过了一些sigaction的行为.
while(!signalHandler.gotExitSignal()) {
switch (poll(&ufds[0], NUM_FDS, POLL_TIMEOUT)) {
case -1: {
throw std::runtime_error("poll error (-1)"); /* ABORT */
}
.
.
Run Code Online (Sandbox Code Playgroud)
我的signalHandler是一个包含sigaction处理的类.
struct sigaction killAction, termAction;
memset(&killAction, 0, sizeof(struct sigaction));
killAction.sa_handler = SignalHandler::ExitHandler;
sigemptyset(&killAction.sa_mask);
killAction.sa_flags = 0;
if(sigaction(SIGTERM, &killAction, NULL) < 0)
throw SignalException("sigaction failed for killAction");
memset(&termAction, 0, sizeof(struct sigaction));
termAction.sa_handler = SignalHandler::ExitHandler;
sigemptyset(&termAction.sa_mask);
termAction.sa_flags = 0;
if(sigaction(SIGTERM, &termAction, NULL) < 0)
throw SignalException("sigaction failed for termAction");
Run Code Online (Sandbox Code Playgroud)
所以我给出的片段循环的预期行为应该是:
怎么了:
我尝试了一个场景,在轮询开关后我睡了2秒然后终止程序 - 它以循环条件正常退出.我在轮询然后接收信号时存在问题.我没有使用SIGHUP信号,它用于告诉程序重新加载其配置,但我设置了一个信号供SIGHUP测试,它终止了我的程序,其轮询错误就像我的其他信号一样.但我不能让我的程序在任何信号上崩溃,我想知道我是否忘记了某些事情.
这是预料之中的.在poll()中阻塞并且信号到达时,轮询将失败并且errno将被设置为EINTR.对于大多数系统调用,您将获得相同的行为.
您可以而且应该检测到这一点(您现在可以更快地突破轮询循环,因为当捕获到信号时poll()将返回.)
while(!signalHandler.gotExitSignal()) {
switch (poll(&ufds[0], NUM_FDS, POLL_TIMEOUT)) {
case -1: {
if (errno == EINTR) {
continue;
}
throw std::runtime_error("poll error (-1)"); /* ABORT */
}
Run Code Online (Sandbox Code Playgroud)
你很可能也想SA_RESTART为sigaction 设置标志.
killAction.sa_flags = SA_RESTART;
Run Code Online (Sandbox Code Playgroud)
这将导致大多数系统调用在捕获信号时不返回错误.阅读sigaction()的联机帮助页以获取更多信息,并阅读man 7信号中的"信号处理程序中断系统调用和库函数"部分.
值得注意的是,无论设置SA_RESTART标志如何,poll()仍将被信号中断(立即返回错误).