使用epoll_wait和signalfd处理信号

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (145)

我正在echo server使用套接字和系统调用来编写自己的代码。我正在使用epoll与许多不同的客户端同时工作,并且与客户端完成的所有操作都是非阻塞的。当服务器打开并且什么都不做时,它就在epoll_wait。现在我想添加使用信号关闭服务器的可能性。例如,我启动服务器bash terminal,然后按ctrl-c,服务器以某种方式处理SIGINT。我的计划是使用signalfd。我创建了新的signalfdepoll使用以下代码将其添加到实例:

    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGTERM);
    sigaddset(&mask, SIGINT);
    signal_fd = signalfd(-1, &mask, 0);

    epoll_event event;
    event.data.fd = signal_fd;
    event.events = EPOLLIN;
    epoll_ctl(fd, EPOLL_CTL_ADD, signal_fd, &event);

然后我希望,epoll等待的时候,我按下ctrl-c,事件epoll发生,它会唤醒然后我用以下代码处理信号:

    if (events[i].data.fd == signal_fd)
    {
        //do something
        exit(0);
    }

虽然实际上服务器只是停止而不处理信号。我做错了什么,解决问题的正确方法是什么?如果我不能正确理解信号,那么应该使用的地方是什么signalfd

提问于
用户回答回答于

虽然实际上服务器只是停止而不处理信号。我做错了什么,解决问题的正确方法是什么?如果我不能正确理解信号,那么应该使用signalfd的地方是什么?

信号处理程序是每个进程。您将信号处理程序保留为默认值,即终止进程。

所以你需要添加这样的东西,

struct sigaction action;
std::memset(&action, 0, sizeof(struct sigaction));
action.sa_handler = your_handler;
sigaction(signum, &action, NULL);

对于您希望应用程序接收中断的每个signum。还处理sigaction的返回值。我的经验是,如果你使用SIG_IGN作为处理程序而不是从“外部”中断epoll_pwait之类的系统调用,但是当你试图通过直接向该程序发送信号从程序本身唤醒线程时它将不起作用线程使用pthread_kill

接下来,您需要屏蔽来自每个线程的所有信号,因此默认情况下没有线程会接收它(否则唤醒随机线程来处理信号)。最简单的方法是在创建任何线程之前在main中执行此操作。

例如,

sigset_t all_signals;
sigemptyset(&all_signals);
sigaddset(&all_signals, signnum); // Repeat for each signum that you use.
sigprocmask(SIG_BLOCK, &all_signals, NULL);

然后,当您希望该线程接收信号时,取消阻塞每个线程的信号。

如果你使用signalfd,那么你不想解除它们 - 系统调用解锁它自己的信号,只需传递适当的掩码(设置位为signalfd(它使用传递的掩码取消阻塞)。另见signalfd的手册页)。

epoll_pwait工作方式不同,就像pselect你解锁你感兴趣的信号一样。你设置一个设置标志的信号处理程序(见上文)。然后在调用之前epoll_pwait阻止信号,然后测试标志并处理它,然后在epoll_pwait没有先解锁信号的情况下调用。epoll_wait返回后,您可以再次解锁信号,以便再次调用您的处理程序。

用户回答回答于

epoll_wait返回-1以及errno == EINTR何时被信号中断。在这种情况下,你需要readsignal_fd

设置信号的信号处理程序SIG_IGN,否则信号可能会终止您的应用程序。

男人信号7

在被信号处理程序中断后,以下接口永远不会重新启动,无论使用什么SA_RESTART; EINTR当信号处理程序中断时,它们总是因错误而失败:

  • 文件描述符多路复用接口:epoll_wait(2),epoll_pwait(2),poll(2),ppoll(2),select(2)和pselect(2)。

扫码关注云+社区

领取腾讯云代金券