Как использовать флаг с sigint для уведомления, когда он был отправлен дважды за одну секунду? - PullRequest
0 голосов
/ 27 февраля 2020

Я новичок в c программировании и борюсь с заданием. Основой кода является наличие 1-секундного таймера (я использую sleep (1)), который отсчитывает, начиная с приращения 1. Каждый раз, когда я отправляю sigINT, я увеличиваю приращение на 1, и счетчик печатает с новый номер. Я использую sigterm, чтобы уменьшить число. Все это работает нормально.

Последняя часть - убить программу, если я использую sigINT дважды за одну секунду. Я попытался сделать это с «флагом», который для меня установлен в 0. Когда вызывается sigINT, увеличьте его на 1. Сделайте сброс до 0, пока l oop. Я попытался написать заявление if, что если приращение больше 1, программа остановится. Но с sleep (0) и flag = 0 сразу после этого я никогда не смогу сделать так, чтобы флаг был больше 1. Я знаю, что это, вероятно, не лучший способ сделать это, но мне не повезло в поиске лучшего решения , Любая помощь приветствуется. Спасибо.

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

int inc = 1;
int flag = 0;

void handle_sigint(int sig_num)
{
    signal(SIGINT, handle_sigint);
    if (inc < 10)
    {
        inc++;
    }
    flag++;
    printf("\nflag=%d\n", flag);
    printf("\nSIGINT received: Increment is now %d\n", inc);
    fflush(stdout);
}

void handle_sigterm(int sig_num)
{
    signal(SIGTERM, handle_sigterm);
    if (inc > 0)
    {
        inc--;
    }
    printf("\nSIGTERM received: Increment is now %d\n", inc);
    fflush(stdout);
}

int main()
{
    int num = 0;
    signal(SIGINT, handle_sigint);
    signal(SIGTERM, handle_sigterm);
    printf("Process ID: %d\n", getpid());
    while (1)
    {
        if (flag > 1)
        {
            pid_t iPid = getpid();
            printf("\nExiting the program now\n"); 
            kill(iPid, SIGKILL);
        }   
        printf("%d\n", num);
        num = num + inc;
        sleep(1);
        flag = 0;
    }
    return 0;
}

1 Ответ

1 голос
/ 27 февраля 2020

Если установлены flag=0 сразу после sleep(1) и непосредственно перед проверкой if(flag>1). Это означает, что между установкой его на ноль и проверкой нет времени, и в это время вы хотите отправлять сигналы SIGINT в вашу программу. Вы установили флаг на ноль в лучшем случае сразу после его проверки.

sleep() вызов прерывается! Если sleep() прерван сигналом, он возвращает количество секунд, оставшихся до режима сна. Для справки прочитайте man sleep. Поскольку «1 секунда» на самом деле не делится на меньший фрагмент, вы можете использовать usleep или просто использовать nanosleep call. nanosleep возвращает -1 и устанавливает errno в EINTR, если сигнал был получен во время сна. Поскольку он возвращает время, оставшееся для сна во втором аргументе, это легко сделать с помощью oop. Вы должны добавить #include <errno.h> для errno и #include <time.h> для nanosleep.

Так что-то вместе:

while (1) {
   if (flag > 1) {
          // some code
   }
   // printf("something");

   // set flag before sleeping!
   flag = 0; 

   // wait a second
   struct timespec rqtp = { 1, 0 };
   while (nanosleep(&rqtp, &rqtp) == -1 && errno == EINTR) {
       // repeat until we slept a full second
   }

}

Примечания:

  • Хороший код! Пожалуйста, придерживайтесь некоторого стиля отступов и отступа для своего кода. Я рекомендую linux стиль кодирования ядра .
  • printf и fflush не являются функцией безопасности сигнала. Вызов их из обработчика сигнала - неопределенное поведение. Не следует вызывать printf из обработчика сигнала.
  • Технически следует использовать тип volatile sig_atomic_t для синхронизации с обработчиком сигнала. Я думаю, что было бы предпочтительнее пометить ваши flag и inc переменные как минимум как volatile.
...