任何信号的C++轮询错误

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)

所以我给出的片段循环的预期行为应该是:

  1. while(!signalHandler.gotExitSignal()){
  2. switch(poll(&ufds [0],NUM_FDS,POLL_TIMEOUT)){
  3. 轮询后做一些清理工作
  4. 转到1
  5. while(!signalHandler.gotExitSignal()){
  6. 打断
  7. switch(poll(&ufds [0],NUM_FDS,POLL_TIMEOUT)){
  8. 轮询后做一些清理工作
  9. 转到1
  10. 打破循环

怎么了:

  1. while(!signalHandler.gotExitSignal()){
  2. switch(poll(&ufds [0],NUM_FDS,POLL_TIMEOUT)){
  3. 轮询后做一些清理工作
  4. 转到1
  5. while(!signalHandler.gotExitSignal()){
  6. 打断
  7. throw std :: runtime_error("poll error(-1)");

我尝试了一个场景,在轮询开关后我睡了2秒然后终止程序 - 它以循环条件正常退出.我在轮询然后接收信号时存在问题.我没有使用SIGHUP信号,它用于告诉程序重新加载其配置,但我设置了一个信号供SIGHUP测试,它终止了我的程序,其轮询错误就像我的其他信号一样.但我不能让我的程序在任何信号上崩溃,我想知道我是否忘记了某些事情.

nos*_*nos 6

这是预料之中的.在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()仍将被信号中断(立即返回错误).