Почему мой обработчик сигнала выполняется только один раз?

2

Я играю с обработкой сигналов в 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

Но если я отправлю второй сигнал прерывания, процесс будет остановлен.

Почему это происходит? Я попробовал прочитать руководство по эксплуатации, чтобы попытаться выяснить, не возникло ли что-то, что сделает обработчик, который я создал, когда сигнал пойман и откат на SIG_DFL, но не смог его обработать.

Спасибо

  • 0
    @ ММ Да, это решило это. Вы хотите сделать сообщение, чтобы я мог пометить его как правильный?
Теги:
system-calls

2 ответа

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

В этом коде:

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 чтобы предотвратить непредвиденное поведение оптимизатора.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню