Обработчик SIGINT запускается только один раз

Это скрипт csh . Проверьте, является ли он исполняемым, иначе выполните chmod u + x settings64.csh и запустите его либо с ./ settings64.csh , либо csh settings.sh

1
14.03.2017, 09:30
2 ответа

signal (2) является частью старого API сигналов, который не всегда удобен в использовании, главным образом потому, что ...

Единственное портативное использование signal () - установить расположение сигнала на SIG_DFL или SIG_IGN . Семантика при использовании signal () для установки обработчика сигналов различается в зависимости от системы (и POSIX.1 явно разрешает это изменение); не используйте его для этой цели.

В исходных системах UNIX, когда обработчик, который был установлен с помощью signal () , был вызван доставкой сигнала, расположение сигнала сбрасывалось на SIG_DFL , и система не блокировала доставку следующих экземпляров сигнала. Система V также предоставляет эту семантику для signal () .

В BSD, когда вызывается обработчик сигнала, расположение сигнала не сбрасывается, и дальнейшие экземпляры сигнала блокируются от доставки во время выполнения обработчика.

В Linux ситуация выглядит следующим образом:

  • Системный вызов ядра signal () обеспечивает семантику System V.
  • По умолчанию в glibc 2 и более поздних версиях функция-оболочка signal () [...] вызывает sigaction (2) с использованием флагов, обеспечивающих семантику BSD.
  • В glibc 2 и новее, если тестовый макрос _BSD_SOURCE не определен, то signal () обеспечивает семантику System V.(Неявное определение по умолчанию _BSD_SOURCE не предоставляется, если вызывается gcc (1) в одном из его стандартных режимов ( -std = xxx или ) -ansi ) или ... см. signal (2) .

Другими словами, существует множество случаев, когда обработчик, установленный с помощью signal , не будет использоваться более одного раза: после одного сигнала определенная вами функция будет отброшена, а обработчик будет сброшен до значения по умолчанию, что для SIGINT означает уничтожение процесса.

Хотя я бы сделал это. рекомендую вам прочитать только что процитированную страницу руководства, лучший способ справиться с этой ситуацией - это, вероятно, прекратить использование сигнала и переключиться на sigaction . На странице руководства вы найдете все подробности вам нужно, но вот небольшой пример:

void sighandler(int signum);

int main(void) {
    struct sigaction sa;
    sa.sa_handler = sighandler;
    sigemptyset(&(sa.sa_mask));
    sigaddset(&(sa.sa_mask), SIGINT);
    sigaction(SIGINT, &sa, NULL);

    int i;
    for(i = 0; i < 5; i++) {
        printf("Sleeping...\n");
        sleep(5);
        printf("Woke up!\n");
    }
}

void sighandler(int signum) {
    printf("Signal caught!\n");
}

Однако важное замечание: как вы, возможно, уже знаете (отсюда ваш «бесконечный» цикл в вашей функции main ), сигналы будут прерывать системные вызовы ( такой как те sleep (3) ) после приема сигнала, независимо от того, обрабатывается ли этот сигнал программой или нет. В моем примере выше программа будет напечатать Проснулся! каждый раз, когда вы убиваете его, потому что он преждевременно завершает вызов сна. Если вы посмотрите на страницу руководства, вы увидите, что вызов должен возвращать количество секунд, оставшихся до сна, когда он был прерван.

2
27.01.2020, 23:19

Еще одно условие, которое здесь не было выделено.

Вы должны установить флаги sa _в структуре sigaction, чтобы обеспечить согласованные результаты.

sa.sa_flags = 0 ; // this works for me

I was tripped up for a good several minutes just now because I had 2 different applications that registered the signal in the same way and only one of them had this issue (catching the signal only once).

After staring at my code for a bit and rereading the man page I realized the different behaviour was because of different nuanced function stack side effects of my 2 applications.

one program registered the signal handler w/ sigaction() super early in main() pretty much before any memory was allocated or any nested functions were entered (this was the program w/ irregular sigaction behaviour).

The other program called sigaction() after some other variables had been declared at the top of main that took up some memory etc and it seems like by a fluke gave it consistent behaviour to initialize the memory in sa.sa_flags to zero most likely (or some number that probably didn't have the SA_RESETHAND bit set).

The fact that the inconsistent application would sometimes initialize registering the signal w/ catch once behaviour and sometimes w/ catch every time behaviour tipped me off to some kind of randomness that could be caused by garbage among other things.

Условные обозначения фрагмента кода быстрого примера в ответе Джона все еще неполны и могут давать противоречивые результаты, поскольку в нем не установлены флаги sa _.

2
27.01.2020, 23:19

Теги

Похожие вопросы