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

标签 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 */
        }
        .
        .

我的 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");

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

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

发生了什么:

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

我尝试了一个场景,在轮询切换之后我睡了 2 秒然后终止了程序 - 它在循环条件下优雅地退出。当我轮询然后收到信号时,问题就存在了。我不使用 SIGHUP 信号,该信号用于告诉程序重新加载其配置,但我为 SIGHUP 设置了一个信号进行测试,它像我的其他信号一样以轮询错误终止了我的程序。但是我不能让我的程序因任何信号而崩溃,我想知道我是否忘记了什么。

最佳答案

这是预料之中的。在 poll() 中阻塞并且信号到达时,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 */
        }

您很可能还想为 sigaction 设置 SA_RESTART 标志。

 killAction.sa_flags = SA_RESTART;

这将导致大多数系统调用在捕获到信号时不返回错误。阅读 sigaction() 的联机帮助页以获取更多信息,并阅读 man 7 signal 中的“信号处理程序中断系统调用和库函数”部分。 .

值得注意的是,无论设置 SA_RESTART 标志,poll() 仍将被信号中断(立即返回错误)。

关于任何信号上的 C++ 轮询错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21313780/

相关文章:

C++ 代码在 cmd 提示符前打印

c++ - 如何通过套接字发送PDF文件?

c - 为什么信号在 Linux 中依赖于平台?

c++ - 我如何打印 4 个不同的字母可以组合成 2 个字母对以填充四个点的所有方式,每个单独的字母恰好出现两次?

c++ - 如何推断 C++11 中的模板参数类型?

c - 在 C 中运行时与应用程序交互

Python,Pyplot - 如何同时 move 两个绘图?

c# - 如何异步运行长时间运行的操作并在 ASP.Net Ajax 中为用户显示加载并轮询结果?

linux - 将负文件描述符传递给轮询

java - 使用 Java 检查数据库是否正在运行