Содержание страницы
18.5. signal – Установка обработчиков для асинхронных событий¶signal – Set handlers for asynchronous events
Этот модуль предоставляет механизмы для использования обработчиков сигналов в Python.
18.5.1. Общие правила¶General rules
Функция signal.signal() позволяет определять пользовательские обработчики, которые выполняются при получении сигнала. Установлено небольшое количество обработчиков по умолчанию: SIGPIPE игнорируется (так что ошибки записи в каналы и сокеты могут сообщаться как обычные исключения Python), а SIGINT преобразуется в исключение KeyboardInterrupt.
Обработчик конкретного сигнала после установки остаётся активным, пока его явно не сбросят (Python эмулирует интерфейс в стиле BSD независимо от базовой реализации), за исключением обработчика SIGCHLD, который следует базовой реализации.
Нет способа временно «блокировать» сигналы в критических секциях (поскольку это поддерживается не во всех разновидностях Unix).
18.5.1.1. Выполнение обработчиков сигналов Python¶Execution of Python signal handlers
Обработчик сигналов Python не выполняется внутри низкоуровневого (C) обработчика сигналов. Вместо этого низкоуровневый обработчик устанавливает флаг, который сообщает виртуальной машине выполнить соответствующий обработчик Python позже (например, на следующей инструкции байткода). Это имеет последствия:
- Нет особого смысла перехватывать синхронные ошибки, такие как SIGFPE или SIGSEGV, вызванные недопустимой операцией в коде C. Python вернётся из обработчика сигнала в код C, который, скорее всего, снова вызовет тот же сигнал, из-за чего Python может зависнуть. Начиная с Python 3.3 можно использовать модуль faulthandler для сообщения о синхронных ошибках.
- Длительное вычисление, реализованное чисто на C (например, сравнение с регулярным выражением по большому объему текста), может выполняться без прерывания сколь угодно долго, независимо от полученных сигналов. Обработчики сигналов Python будут вызваны по завершении вычисления.
18.5.1.2. Сигналы и потоки¶Signals and threads
Обработчики сигналов Python всегда выполняются в главном потоке Python, даже если сигнал был получен в другом потоке. Это означает, что сигналы нельзя использовать как средство межпоточного взаимодействия. Вместо этого можно использовать примитивы синхронизации из модуля threading.
Кроме того, только главный поток может устанавливать новый обработчик сигнала.
18.5.2. Содержание модуля¶Module contents
Переменные, определённые в модуле signal:
- signal.SIG_DFL¶
Это один из двух стандартных вариантов обработки сигналов; он просто выполняет действие по умолчанию для сигнала. Например, на большинстве систем действие по умолчанию для SIGQUIT – сбросить дамп ядра и завершиться, а для SIGCHLD – просто игнорировать его.
- signal.SIG_IGN¶
Это еще один стандартный обработчик сигнала, который просто игнорирует данный сигнал.
- SIG*
Все номера сигналов определены символически. Например, сигнал отбоя (hangup) определён как signal.SIGHUP; имена переменных совпадают с именами, используемыми в программах на C, как в <signal.h>. Страница руководства Unix для ‘signal()‘ содержит список существующих сигналов (в некоторых системах это signal(2), в других список находится в signal(7)). Обратите внимание, что не все системы определяют один и тот же набор имён сигналов; этот модуль определяет только те имена, которые определены системой.
- signal.CTRL_C_EVENT¶
Сигнал, соответствующий событию нажатия клавиш CTRL+C. Этот сигнал можно использовать только с os.kill().
Доступность: Windows.
Новое в версии 3.2.
- signal.CTRL_BREAK_EVENT¶
Сигнал, соответствующий событию нажатия клавиш CTRL+BREAK. Этот сигнал можно использовать только с os.kill().
Доступность: Windows.
Новое в версии 3.2.
- signal.NSIG¶
На единицу больше номера самого высокого сигнала.
- signal.ITIMER_REAL¶
Уменьшает интервальный таймер в реальном времени и отправляет SIGALRM по истечении.
- signal.ITIMER_VIRTUAL¶
Уменьшает интервальный таймер только во время выполнения процесса и отправляет SIGVTALRM по истечении.
- signal.ITIMER_PROF¶
Уменьшает интервальный таймер как при выполнении процесса, так и при выполнении системой от имени процесса. В паре с ITIMER_VIRTUAL этот таймер обычно используется для профилирования времени, затраченного приложением в пользовательском и ядерном пространстве. SIGPROF доставляется по истечении времени.
- signal.SIG_BLOCK¶
Возможное значение для параметра how функции pthread_sigmask(), указывающее, что сигналы необходимо заблокировать.
Новое в версии 3.3.
- signal.SIG_UNBLOCK¶
Возможное значение для параметра how функции pthread_sigmask(), указывающее, что сигналы должны быть разблокированы.
Новое в версии 3.3.
- signal.SIG_SETMASK¶
Возможное значение для параметра how функции pthread_sigmask(), указывающее, что маска сигналов должна быть заменена.
Новое в версии 3.3.
Модуль signal определяет одно исключение:
- exception signal.ItimerError¶
Возникает при ошибке в реализации setitimer() или getitimer(). Ожидайте этой ошибки, если в setitimer() передан неверный интервальный таймер или отрицательное время. Эта ошибка является подтипом OSError.
Модуль 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).)
См. также sigwait(), sigwaitinfo(), sigtimedwait() и sigpending().
- signal.pthread_kill(thread_id, signum)¶
Отправляет сигнал signum потоку thread_id, другому потоку в том же процессе, что и вызывающий. Целевой поток может выполнять любой код (Python или нет). Однако если целевой поток выполняет интерпретатор Python, обработчики сигналов Python будут выполнены главным потоком. Поэтому единственный смысл отправки сигнала конкретному потоку Python – заставить выполняющийся системный вызов завершиться с ошибкой InterruptedError.
Используйте threading.get_ident() или атрибут ident объектов threading.Thread, чтобы получить подходящее значение для thread_id.
Если signum равно 0, сигнал не отправляется, но проверка ошибок всё равно выполняется; это можно использовать для проверки, работает ли целевой поток до сих пор.
Доступность: Unix (см. страницу руководства pthread_kill(3) для получения дополнительной информации).
См. также os.kill().
Новое в версии 3.3.
- signal.pthread_sigmask(how, mask)¶
Получает и/или изменяет маску сигналов вызывающего потока. Маска сигналов – это набор сигналов, доставка которых в настоящий момент заблокирована для вызывающей стороны. Возвращает старую маску сигналов в виде набора сигналов.
Поведение вызова зависит от значения how следующим образом.
- SIG_BLOCK: набор блокируемых сигналов является объединением текущего набора и аргумента mask.
- SIG_UNBLOCK: сигналы из mask удаляются из текущего набора блокируемых сигналов. Допускается попытка разблокировать сигнал, который не был заблокирован.
- SIG_SETMASK: набор блокируемых сигналов устанавливается равным аргументу mask.
mask – это набор номеров сигналов (например, {signal.SIGINT, signal.SIGTERM}). Используйте range(1, signal.NSIG) для полной маски, включающей все сигналы.
Например, signal.pthread_sigmask(signal.SIG_BLOCK, []) читает маску сигналов вызывающего потока.
Доступность: Unix. См. страницы руководства sigprocmask(3) и pthread_sigmask(3) для получения дополнительной информации.
См. также pause(), sigpending() и sigwait().
Новое в версии 3.3.
- 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 как один байт. Это может быть использовано библиотекой для пробуждения вызова poll или select, позволяя полностью обработать сигнал.
Возвращается старый дескриптор пробуждения. fd должен быть неблокирующим. Библиотека должна удалить все байты перед повторным вызовом poll или select.
Используйте, например, struct.unpack('%uB' % len(data), data) для декодирования списка номеров сигналов.
Когда потоки включены, эту функцию можно вызывать только из основного потока; попытка вызова из других потоков приведёт к возникновению исключения 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.
- signal.sigpending()¶
Проверяет набор сигналов, ожидающих доставки вызывающему потоку (т.е. сигналы, которые были подняты, пока были заблокированы). Возвращает набор ожидающих сигналов.
Доступность: Unix (см. страницу руководства sigpending(2) для получения дополнительной информации).
См. также pause(), pthread_sigmask() и sigwait().
Новое в версии 3.3.
- signal.sigwait(sigset)¶
Приостанавливает выполнение вызывающего потока до доставки одного из сигналов, указанных в наборе сигналов sigset. Функция принимает сигнал (удаляет его из списка ожидающих сигналов) и возвращает номер сигнала.
Доступность: Unix (см. страницу руководства sigwait(3) для получения дополнительной информации).
См. также pause(), pthread_sigmask(), sigpending(), sigwaitinfo() и sigtimedwait().
Новое в версии 3.3.
- signal.sigwaitinfo(sigset)¶
Приостанавливает выполнение вызывающего потока до поступления одного из сигналов, указанных в наборе сигналов sigset. Функция принимает сигнал и удаляет его из списка ожидающих сигналов. Если один из сигналов в sigset уже ожидает обработки в вызывающем потоке, функция немедленно вернётся с информацией об этом сигнале. Обработчик сигнала для доставленного сигнала не вызывается. Функция вызывает исключение InterruptedError, если она была прервана сигналом, не входящим в sigset.
Возвращаемое значение – объект, представляющий данные, содержащиеся в структуре siginfo_t, а именно: si_signo, si_code, si_errno, si_pid, si_uid, si_status, si_band.
Доступность: Unix (см. страницу руководства sigwaitinfo(2) для получения дополнительной информации).
См. также pause(), sigwait() и sigtimedwait().
Новое в версии 3.3.
- signal.sigtimedwait(sigset, timeout)¶
Как и sigwaitinfo(), но принимает дополнительный аргумент timeout, задающий тайм-аут. Если timeout указан как 0, выполняется опрос. Возвращает None, если произошёл тайм-аут.
Доступно: Unix (см. man-страницу sigtimedwait(2) для получения дополнительной информации).
См. также pause(), sigwait() и sigwaitinfo().
Новое в версии 3.3.
18.5.3. Пример¶Example
Вот минимальный пример программы. В ней используется функция alarm() для ограничения времени ожидания открытия файла; это полезно, если файл относится к последовательному устройству, которое может быть выключено, и обычно это приводит к тому, что os.open() зависает на неопределённый срок. Решение – установить 5-секундный будильник перед открытием файла; если операция займёт слишком много времени, будет отправлен сигнал будильника, и обработчик вызовет исключение.
import signal, os
def handler(signum, frame):
print('Signal handler called with signal', signum)
raise OSError("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) # Отключить будильник