Документация Python неофициальный перевод
Содержание страницы

17.4. signal – Установка обработчиков асинхронных событийsignal – Set handlers for asynchronous events

Этот модуль предоставляет механизмы для использования обработчиков сигналов в Python. Несколько общих правил работы с сигналами и их обработчиками:

  • Обработчик конкретного сигнала после установки остаётся активным, пока его явно не сбросят (Python эмулирует интерфейс в стиле BSD независимо от базовой реализации), за исключением обработчика SIGCHLD, который следует базовой реализации.
  • Нет способа временно «блокировать» сигналы в критических секциях (поскольку это поддерживается не во всех разновидностях Unix).
  • Хотя с точки зрения пользователя Python обработчики сигналов вызываются асинхронно, они могут возникнуть только между «атомарными» инструкциями интерпретатора Python. Это означает, что сигналы, поступающие во время длительных вычислений, реализованных чисто на C (например, при сопоставлении регулярных выражений с большими объёмами текста), могут быть задержаны на произвольное время.
  • Когда сигнал поступает во время операции ввода-вывода, возможно, что после возврата из обработчика сигнала операция ввода-вывода возбудит исключение. Это зависит от семантики прерывания системных вызовов в конкретной Unix-системе.
  • Поскольку обработчик сигналов C всегда возвращается, нет особого смысла перехватывать синхронные ошибки, такие как SIGFPE или SIGSEGV.
  • По умолчанию Python устанавливает небольшое количество обработчиков сигналов: SIGPIPE игнорируется (поэтому ошибки записи в каналы и сокеты могут быть сообщены как обычные исключения Python), а SIGINT преобразуется в исключение KeyboardInterrupt. Все они могут быть переопределены.
  • Необходимо соблюдать осторожность при использовании сигналов и потоков в одной программе. Основное, что нужно помнить при одновременной работе с сигналами и потоками: всегда выполняйте операции signal() в главном потоке выполнения. Любой поток может выполнить alarm(), getsignal(), pause(), setitimer() или getitimer(); только главный поток может установить новый обработчик сигнала, и только главный поток будет получать сигналы (это обеспечивается модулем Python signal, даже если базовая реализация потоков поддерживает отправку сигналов отдельным потокам). Это означает, что сигналы нельзя использовать как средство межпоточной связи. Вместо этого используйте блокировки.

Переменные, определённые в модуле signal:

signal.SIG_DFL
Это один из двух стандартных вариантов обработки сигналов; он просто выполняет действие по умолчанию для сигнала. Например, на большинстве систем действие по умолчанию для SIGQUIT – сбросить дамп ядра и завершиться, а для SIGCHLD – просто игнорировать его.
signal.SIG_IGN
Это еще один стандартный обработчик сигнала, который просто игнорирует данный сигнал.
SIG*
Все номера сигналов определены символически. Например, сигнал отбоя (hangup) определён как signal.SIGHUP; имена переменных совпадают с именами, используемыми в программах на C, как в <signal.h>. Страница руководства Unix для ‘signal()‘ содержит список существующих сигналов (в некоторых системах это signal(2), в других список находится в signal(7)). Обратите внимание, что не все системы определяют один и тот же набор имён сигналов; этот модуль определяет только те имена, которые определены системой.
signal.NSIG
На единицу больше номера самого высокого сигнала.
signal.ITIMER_REAL
Уменьшает интервальный таймер в реальном времени и доставляет SIGALRM по истечении времени.
signal.ITIMER_VIRTUAL
Уменьшает интервальный таймер только во время выполнения процесса и отправляет SIGVTALRM по истечении.
signal.ITIMER_PROF
Уменьшает интервальный таймер как при выполнении процесса, так и при выполнении системой от имени процесса. В паре с ITIMER_VIRTUAL этот таймер обычно используется для профилирования времени, затраченного приложением в пользовательском и ядерном пространстве. SIGPROF доставляется по истечении времени.

Модуль signal определяет одно исключение:

exception signal.ItimerError
Возбуждается для сообщения об ошибке в реализации setitimer() или getitimer(). Ожидайте эту ошибку, если в setitimer() передан недопустимый интервальный таймер или отрицательное время. Эта ошибка является подтипом IOError.

Модуль signal определяет следующие функции:

signal.alarm(time)
Если time не равно нулю, эта функция запрашивает отправку сигнала SIGALRM процессу через time секунд. Любой ранее запланированный сигнал отменяется (в любой момент времени может быть запланирован только один сигнал). Возвращаемое значение – количество секунд до момента, когда должен был быть доставлен любой ранее установленный сигнал. Если time равно нулю, сигнал не планируется, а любой запланированный отменяется. Если возвращаемое значение равно нулю, сигнал в данный момент не запланирован. (См. man-страницу Unix alarm(2).) Доступность: Unix.
signal.getsignal(signalnum)
Возвращает текущий обработчик сигнала для сигнала signalnum. Возвращаемое значение может быть вызываемым объектом Python или одним из специальных значений: signal.SIG_IGN, signal.SIG_DFL или None. Здесь signal.SIG_IGN означает, что сигнал ранее игнорировался, signal.SIG_DFL означает, что ранее использовался способ обработки сигнала по умолчанию, а None означает, что предыдущий обработчик сигнала не был установлен из Python.
signal.pause()
Заставляет процесс спать до получения сигнала; затем будет вызван соответствующий обработчик. Ничего не возвращает. Недоступно в Windows. (См. страницу руководства Unix signal(2).)
signal.setitimer(which, seconds[, interval])

Устанавливает заданный интервальный таймер (один из signal.ITIMER_REAL, signal.ITIMER_VIRTUAL или signal.ITIMER_PROF), указанный which, чтобы он сработал через seconds (принимается число с плавающей запятой, в отличие от alarm()) и после этого каждые interval секунд. Интервальный таймер, указанный which, можно сбросить, установив seconds в ноль.

Когда интервальный таймер срабатывает, процессу отправляется сигнал. Отправляемый сигнал зависит от используемого таймера; signal.ITIMER_REAL доставляет SIGALRM, signal.ITIMER_VIRTUAL отправляет SIGVTALRM, а signal.ITIMER_PROF доставляет SIGPROF.

Старые значения возвращаются в виде кортежа: (delay, interval).

Попытка передать недопустимый интервальный таймер вызовет ItimerError. Доступность: Unix.

signal.getitimer(which)
Возвращает текущее значение указанного интервального таймера, заданного через which. Доступность: Unix.
signal.set_wakeup_fd(fd)

Устанавливает fd пробуждения в fd. Когда получен сигнал, в fd записывается один '\0' байт. Это может использоваться библиотекой для пробуждения вызова poll или select, чтобы сигнал был полностью обработан.

Возвращается старый дескриптор пробуждения. fd должен быть неблокирующим. Библиотека должна удалить все байты перед повторным вызовом poll или select.

Когда потоки включены, эту функцию можно вызывать только из основного потока; попытка вызова из других потоков приведёт к возникновению исключения ValueError.

signal.siginterrupt(signalnum, flag)

Изменяет поведение перезапуска системных вызовов: если flag равно False, системные вызовы будут перезапущены при прерывании сигналом signalnum, в противном случае системные вызовы будут прерваны. Ничего не возвращает. Доступность: Unix (см. man-страницу siginterrupt(3) для получения дополнительной информации).

Обратите внимание, что установка обработчика сигнала с помощью signal() сбросит поведение перезапуска на прерываемое, неявно вызывая siginterrupt() со значением flag, равным true, для данного сигнала.

signal.signal(signalnum, handler)

Устанавливает обработчик сигнала signalnum как функцию handler. handler может быть вызываемым объектом Python, принимающим два аргумента (см. ниже), или одним из специальных значений signal.SIG_IGN или signal.SIG_DFL. Ранее установленный обработчик сигнала будет возвращён (см. описание getsignal() выше). (См. страницу руководства Unix signal(2).)

Когда потоки включены, эту функцию можно вызывать только из основного потока; попытка вызова из других потоков приведёт к возникновению исключения ValueError.

handler вызывается с двумя аргументами: номером сигнала и текущим стековым кадром (None или объект кадра; описание объектов кадра см. в описании иерархии типов или в описаниях атрибутов в модуле inspect).

В Windows signal() можно вызывать только с SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV или SIGTERM. В любом другом случае будет вызвано ValueError.

17.4.1. ПримерExample

Вот минимальный пример программы. В ней используется функция alarm() для ограничения времени ожидания открытия файла; это полезно, если файл относится к последовательному устройству, которое может быть выключено, и обычно это приводит к тому, что os.open() зависает на неопределённый срок. Решение – установить 5-секундный будильник перед открытием файла; если операция займёт слишком много времени, будет отправлен сигнал будильника, и обработчик вызовет исключение.

import signal, os

def handler(signum, frame):
    print('Signal handler called with signal', signum)
    raise IOError("Couldn't open device!")

# Установить обработчик сигнала и 5-секундный будильник
signal.signal(signal.SIGALRM, handler)
signal.alarm(5)

# Этот вызов open() может зависнуть навсегда
fd = os.open('/dev/ttyS0', os.O_RDWR)

signal.alarm(0)          # Отключить будильник