为什么我的信号处理程序只执行一次?

时间:2018-09-23 23:33:55

标签: c++ unix system-calls

我正在使用UNIX和C ++处理信号,并且遇到了这个问题。我正在尝试编写一个计数为10(每秒一个数字)的程序,当用户尝试使用SIGINT(如CTRL + C)中断它时,它会显示一条消息,告诉它无论如何都将继续计数。

到目前为止,我知道了:

#include <iostream>
#include <signal.h>
#include <zconf.h>

using namespace std;

sig_atomic_t they_want_to_interrupt = 0;
void sigint_handler(int signum) {
    assert(signum == SIGINT);
    they_want_to_interrupt = 1;
}

void register_handler() {
    struct sigaction sa;
    sigemptyset(&sa.sa_mask);
    sigaddset(&sa.sa_mask, SIGINT);
    sa.sa_handler = sigint_handler;
    sigaction(SIGINT, &sa, 0);
}

int main() {
    register_handler();
    cout << "Hi! We'll count to a hundred no matter what" << endl;
    for (int i = 1; i <= 100; i++) {
        if (they_want_to_interrupt == 1) {
            cout << endl << "DON'T INTERRUPT ME WHILE I'M COUNTING! I'll count ALL THE WAY THROUGH!!!" << endl;
            they_want_to_interrupt = 0;
        }
        cout << i << " " << flush;
        sleep(1);
    }
    cout << "Done!" << endl;
    return 0;
}

现在,我第一次发送中断信号,它可以正常工作:

Hi! We'll count to a hundred no matter what
1 2 ^C
DON'T INTERRUPT ME WHILE I'M COUNTING! I'll count ALL THE WAY THROUGH!!!
3 4

但是如果我发送 second 中断信号,该过程将停止。

为什么会发生?我尝试阅读有关“ sigaction”的手册,以尝试查看是否有某些东西会使捕获到的信号并回滚到SIG_DFL时不会弹出我创建的处理程序,但无法解决。

谢谢

2 个答案:

答案 0 :(得分:2)

您可以在每次发送信号时重置信号处理程序。我已经看到了在重复预期信号时处理SIGUSR的情况。

#include <iostream>
#include <cassert>
#include <signal.h>
#include <zconf.h>

using namespace std;

void register_handler();
sig_atomic_t they_want_to_interrupt = 0;
void sigint_handler(int signum) {
    assert(signum == SIGINT);
    they_want_to_interrupt = 1;
    register_handler();
}

void register_handler() {
    struct sigaction sa;
    sigemptyset(&sa.sa_mask);
    sigaddset(&sa.sa_mask, SIGINT);
    sa.sa_handler = sigint_handler;
    sigaction(SIGINT, &sa, 0);
}

int main() {
    register_handler();
    cout << "Hi! We'll count to a hundred no matter what" << endl;
    for (int i = 1; i <= 100; i++) {
        if (they_want_to_interrupt == 1) {
            cout << endl << "DON'T INTERRUPT ME WHILE I'M COUNTING! I'll count ALL THE WAY THROUGH!!!" << endl;
            they_want_to_interrupt = 0;
        }
        cout << i << " " << flush;
        sleep(1);
    }
    cout << "Done!" << endl;
    return 0;
}

答案 1 :(得分:1)

在此代码中:

struct sigaction sa;
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, SIGINT);
sa.sa_handler = sigint_handler;
sigaction(SIGINT, &sa, 0);

sa.sa_flags字段(和其他字段)未初始化,这可能会导致意外结果。最好在开始时将结构零初始化,例如:

struct sigaction sa = { 0 };

此外,sig_atomic_t标志应声明为volatile,以防止优化程序引入意外行为。