Поиск…


Синтаксис

  • void (* signal (int sig, void (* func) (int))) (int);

параметры

параметр подробности
сиг Сигнал для установки обработчика сигналов, один из SIGABRT , SIGFPE , SIGILL , SIGTERM , SIGINT , SIGSEGV или некоторое определенное значение реализации
FUNC Обработчик сигнала, который является одним из следующих: SIG_DFL , для обработчика по умолчанию, SIG_IGN для игнорирования сигнала или указателя функции с сигнатурой void foo(int sig); ,

замечания

Использование обработчиков сигналов только с гарантиями из стандарта C накладывает различные ограничения, которые могут или не могут быть выполнены в пользовательском обработчике сигналов.

  • Если функция, определенная пользователем, возвращается при обработке SIGSEGV , SIGFPE , SIGILL или любого другого аппаратного прерывания, определяемого реализацией, поведение не определено стандартом C. Это связано с тем, что интерфейс C не дает средств для изменения неисправного состояния (например, после деления на 0 ), и поэтому при возврате программа находится в точно таком же ошибочном состоянии, что и до того, как произошло прерывание аппаратного обеспечения.

  • Если пользовательская функция была вызвана в результате вызова abort или raise , обработчик сигнала не может снова вызвать raise .

  • Сигналы могут поступать в середине любой операции, и поэтому неделимость операций может вообще не гарантироваться, и обработка сигналов не работает с оптимизацией. Поэтому все изменения данных в обработчике сигналов должны быть в переменных

    • типа sig_atomic_t (все версии) или атомарного типа без блокировки (поскольку C11, необязательный)
    • которые являются volatile .
  • Другие функции из стандартной библиотеки C обычно не будут соблюдать эти ограничения, поскольку они могут изменять переменные в глобальном состоянии программы. Стандарт С только делает гарантии для abort , _Exit (с С99), quick_exit (с С11), signal (для того же самого числа сигналов), а также некоторые атомарные операции (начиная с С11).

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

  • Обычно системы имеют свой собственный список функций, которые безопасны для асинхронного сигнала , то есть из функций библиотеки C, которые могут использоваться из обработчика сигналов. Например, часто функция printf входит в число этих функций.

  • В частности, стандарт C не определяет многое о взаимодействии с его интерфейсом потоков (начиная с C11) или с любыми конкретными библиотеками потоков, такими как потоки POSIX. Такие платформы должны сами определять взаимодействие таких библиотек потоков с сигналами.

Обработка сигналов с помощью «signal ()»

Номера сигналов могут быть синхронными (например, SIGSEGV - segmentation fault), когда они срабатывают при неправильной работе самой программы или асинхронной (например, SIGINT - интерактивное внимание), когда они инициируются извне программы, например, Cntrl-C клавиши Cntrl-C .

Функция signal() является частью стандарта ISO C и может использоваться для назначения функции для обработки определенного сигнала

#include <stdio.h>  /* printf() */
#include <stdlib.h> /* abort()  */
#include <signal.h> /* signal() */

void handler_nonportable(int sig)
{
    /* undefined behavior, maybe fine on specific platform */
    printf("Catched: %d\n", sig);
    
    /* abort is safe to call */
    abort();
}

sig_atomic_t volatile finished = 0;

void handler(int sig)
{
    switch (sig) {
    /* hardware interrupts should not return */
    case SIGSEGV:
    case SIGFPE:
    case SIGILL:
C11
      /* quick_exit is safe to call */
      quick_exit(EXIT_FAILURE);
C11
      /* use _Exit in pre-C11 */
      _Exit(EXIT_FAILURE);
    default:
       /* Reset the signal to the default handler, 
          so we will not be called again if things go
          wrong on return. */
      signal(sig, SIG_DFL);
      /* let everybody know that we are finished */
      finished = sig;
      return;
   }
}

int main(void)
{

    /* Catch the SIGSEGV signal, raised on segmentation faults (i.e NULL ptr access */
    if (signal(SIGSEGV, &handler) == SIG_ERR) {
        perror("could not establish handler for SIGSEGV");
        return EXIT_FAILURE;
    }

    /* Catch the SIGTERM signal, termination request */
    if (signal(SIGTERM, &handler) == SIG_ERR) {
        perror("could not establish handler for SIGTERM");
        return EXIT_FAILURE;
    }

    /* Ignore the SIGINT signal, by setting the handler to `SIG_IGN`. */
    signal(SIGINT, SIG_IGN);


    /* Do something that takes some time here, and leaves
       the time to terminate the program from the keyboard. */

    /* Then: */

    if (finished) {
       fprintf(stderr, "we have been terminated by signal %d\n", (int)finished);
        return EXIT_FAILURE;
    }


    /* Try to force a segmentation fault, and raise a SIGSEGV */
    {
      char* ptr = 0;
      *ptr = 0;
    }

    /* This should never be executed */
    return EXIT_SUCCESS;
}

Использование signal() налагает важные ограничения на то, что вам разрешено делать внутри обработчиков сигналов, см. Примечания для получения дополнительной информации.

POSIX рекомендует использовать sigaction() вместо signal() из-за его неопределенного поведения и значительных вариантов реализации. POSIX также определяет гораздо больше сигналов, чем стандарт ISO C, включая SIGUSR1 и SIGUSR2 , которые могут использоваться свободно программистом для любых целей.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow