2 обработчика SIGINT для выхода из программы после получения второго сигнала SIGINT в течение одной секунды - PullRequest
0 голосов
/ 24 февраля 2020

Моя программа должна печатать число каждую секунду от 0 до 10 и никогда не больше 10. Я поместил это в свой основной l oop с помощью While (1), чтобы сделать это навсегда.

У меня есть обработчик SIGINT для увеличения номера 1 или -1 для SIGINT и SIGTERM соответственно.

Я пытаюсь реализовать второй обработчик для захвата второго сигнала SIGINT в течение одной секунды после первый, чтобы выйти из программы, но мой второй обработчик (sig_handler_2) никогда не достигается. Что я делаю неправильно?

Исходный код:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

int number = 0;

void sig_handler_2(int sig) {
    printf("Exiting the program now \n");
    signal(SIGINT, SIG_DFL);
}

void sig_handler_1(int sig) {
    signal(SIGINT, sig_handler_2);
    if (sig == SIGINT) {
        if (number > 9) {
        printf(" SIGINT received but number is > 9, cannot increment \n");
        }
      else {
          printf(" SIGINT received: Increment is now %d \n", number);
      }
    }
    if (sig == SIGTERM) {
      if (number <= 0) {
          printf(" SIGTERM received but number <= 0, cannot increment \n");
      }
      else {
          number --;
          printf(" SIGTERM received: Increment is now %d \n", number);
          printf("%d \n", number);
      }
    }
}

int main() {
    while (1) {
        signal(SIGINT, sig_handler_1);
        signal(SIGTERM, sig_handler_1);
        if (number > 9) {
            printf("%d \n", number);
            number = 0;
        }
        else {
            printf("%d \n", number);
            number ++;
        }
        sleep(1);
    }
}`

1 Ответ

0 голосов
/ 24 февраля 2020

Непосредственная проблема заключается в том, что ваш основной l oop всегда сбрасывает обработчик сигнала, и вы недостаточно быстры для генерации этого второго сигнала, прежде чем ваш код сбрасывает расположение SIGINT в handler1.

step  what
----  ----------------------------------------
  0   main/set SIGINT disposition -> handler1
  1   main/sleep(1) -> ...
  2   <SIGINT>
  3   handler1/set SIGINT disposition -> handler2  // Note: SIGINT delivery is probably
                                                   //       blocked during handler1()
  4   <return to main>
  5   main/sleep() -> EINTR
  6   main/set SIGINT disposition -> handler1      // Another SIGINT will now do the same
                                                   // as before
  7   main/sleep(1) -> ...

Вот почему, как вы заметили в другом месте, sleep() внутри первого обработчика сигнала работает: он дает вам достаточно времени для генерации INT, пока расположение этого сигнала установлено на handler2.

Теперь есть ряд вещи, которые я предлагаю вам изменить в этой реализации.

Вытяните signal() звонки из вашего основного l oop. Не ясно, что поведение имеет смысл в логах c вашей программы.

Пожалуйста, используйте sigaction(), а не signal(). sigaction() более сложный, и он заставляет вас указать важные вещи, такие как: sleep() возобновится после сигнала (SA_RESTART)? Будет ли ваш обработчик позволять сигналам прерывать себя (sa_mask, SA_NODEFER)? Как много вы хотите знать о сгенерированном сигнале (SA_SIGINFO)? Хотите ли вы обработчик «одного выстрела» (SA_RESETHAND)?

Любое использование signal() должно отвечать на все эти вопросы неявно, и прискорбная историческая реальность заключается в том, что разные платформы имели разные ответы на эти вопросы. Используйте sigaction().

Вы также захотите удалить printf() из ваших обработчиков сигналов .

Пуристы также порекомендуют вам манипулировать volatile sig_atomic_t переменная внутри обработчика, а не простая int.

...