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

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


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

Общие правилаGeneral rules

Функция signal.signal() позволяет определять пользовательские обработчики, выполняемые при получении сигнала. Небольшое количество обработчиков по умолчанию установлено: сигнал SIGPIPE игнорируется (поэтому ошибки записи в каналы и сокеты могут сообщаться как обычные исключения Python), а сигнал SIGINT преобразуется в исключение KeyboardInterrupt, если родительский процесс не изменил его.

Обработчик конкретного сигнала после установки остается активным до явной переустановки (Python эмулирует интерфейс в стиле BSD независимо от реализации), за исключением обработчика для SIGCHLD, который следует базовой реализации.

Выполнение обработчиков сигналов PythonExecution of Python signal handlers

Обработчик сигналов Python не выполняется внутри низкоуровневого (C) обработчика сигналов. Вместо этого низкоуровневый обработчик устанавливает флаг, который сообщает виртуальной машине выполнить соответствующий обработчик Python позже (например, на следующей инструкции байткода). Это имеет последствия:

  • Ловить синхронные ошибки вроде SIGFPE или SIGSEGV, вызванные недопустимой операцией в коде C, не имеет смысла. Python вернется от обработчика сигнала к коду C, который, скорее всего, снова возбудит тот же сигнал, что приведет к зависанию Python. Начиная с Python 3.3 можно использовать модуль faulthandler для сообщения о синхронных ошибках.

  • Длительное вычисление, реализованное чисто на C (например, сравнение с регулярным выражением по большому объему текста), может выполняться без прерывания сколь угодно долго, независимо от полученных сигналов. Обработчики сигналов Python будут вызваны по завершении вычисления.

Сигналы и потокиSignals and threads

Обработчики сигналов Python всегда выполняются в главном потоке Python, даже если сигнал был получен в другом потоке. Это означает, что сигналы нельзя использовать для межпоточной коммуникации. Вместо этого можно использовать примитивы синхронизации из модуля threading.

Кроме того, только главный поток может устанавливать новый обработчик сигнала.

Содержимое модуляModule contents

Изменено в версии 3.5: signal (SIG*), handler (SIG_DFL, SIG_IGN) и sigmask (SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK) и перечисленные ниже константы были преобразованы в enums. Функции getsignal(), pthread_sigmask(), sigpending() и sigwait() возвращают человекочитаемые enums.

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

signal.SIG_DFL

Это один из двух стандартных вариантов обработки сигналов; он просто выполняет функцию по умолчанию для сигнала. Например, на большинстве систем действие по умолчанию для SIGQUIT – сбросить дамп ядра и завершиться, тогда как действие по умолчанию для SIGCHLD – просто игнорировать его.

signal.SIG_IGN

Это еще один стандартный обработчик сигнала, который просто игнорирует данный сигнал.

signal.SIGABRT

Сигнал прерывания от abort(3).

signal.SIGALRM

Сигнал таймера от alarm(2).

Доступность: Unix.

signal.SIGBREAK

Прерывание с клавиатуры (CTRL + BREAK).

Доступность: Windows.

signal.SIGBUS

Ошибка шины (неверный доступ к памяти).

Доступность: Unix.

signal.SIGCHLD

Дочерний процесс остановлен или завершён.

Доступность: Unix.

signal.SIGCLD

Псевдоним для SIGCHLD.

signal.SIGCONT

Продолжить процесс, если он в данный момент остановлен

Доступность: Unix.

signal.SIGFPE

Исключение с плавающей запятой. Например, деление на ноль.

См. также

ZeroDivisionError возникает, когда второй аргумент операции деления или взятия остатка равен нулю.

signal.SIGHUP

Обнаружен обрыв связи на управляющем терминале или завершение управляющего процесса.

Доступность: Unix.

signal.SIGILL

Недопустимая инструкция.

signal.SIGINT

Прерывание с клавиатуры (CTRL + C).

Действие по умолчанию – возбудить KeyboardInterrupt.

signal.SIGKILL

Сигнал уничтожения.

Его нельзя перехватить, заблокировать или проигнорировать.

Доступность: Unix.

signal.SIGPIPE

Разрыв канала: запись в канал без читателей.

Действие по умолчанию – игнорировать сигнал.

Доступность: Unix.

signal.SIGSEGV

Ошибка сегментации: неверная ссылка на память.

signal.SIGTERM

Сигнал завершения.

signal.SIGUSR1

Пользовательский сигнал 1.

Доступность: Unix.

signal.SIGUSR2

Пользовательский сигнал 2.

Доступность: Unix.

signal.SIGWINCH

Сигнал изменения размера окна.

Доступность: Unix.

SIG*

Все номера сигналов определены символически. Например, сигнал сброса определен как signal.SIGHUP; имена переменных идентичны именам, используемым в программах на C, как в <signal.h>. В man-странице 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.

Новое в версии 3.3: Раньше эта ошибка была подтипом IOError, который теперь является синонимом OSError.

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

signal.alarm(time)

Если time не равен нулю, эта функция запрашивает отправку сигнала SIGALRM процессу через time секунд. Любой ранее запланированный сигнал отменяется (в любой момент может быть запланирован только один сигнал). Возвращаемое значение – количество секунд до отправки предыдущего запланированного сигнала. Если time равно нулю, никакой сигнал не планируется, а любой запланированный отменяется. Если возвращаемое значение равно нулю, сигнал в настоящее время не запланирован.

Доступность: Unix. См. справочную страницу alarm(2) для получения дополнительной информации.

signal.getsignal(signalnum)

Возвращает текущий обработчик сигнала signalnum. Возвращаемое значение может быть вызываемым объектом Python или одним из специальных значений signal.SIG_IGN, signal.SIG_DFL или None. Здесь signal.SIG_IGN означает, что сигнал ранее игнорировался, signal.SIG_DFL означает, что ранее использовался способ обработки сигнала по умолчанию, а None означает, что предыдущий обработчик сигнала не был установлен из Python.

signal.strsignal(signalnum)

Возвращает системное описание сигнала signalnum, например «Interrupt», «Segmentation fault» и т. д. Возвращает None, если сигнал не распознан.

Новое в версии 3.8.

signal.valid_signals()

Возвращает набор допустимых номеров сигналов на этой платформе. Он может быть меньше range(1, NSIG), если некоторые сигналы зарезервированы системой для внутреннего использования.

Новое в версии 3.8.

signal.pause()

Приостанавливает выполнение процесса до получения сигнала; затем будет вызван соответствующий обработчик. Ничего не возвращает.

Доступность: Unix. См. справочную страницу signal(2) для получения дополнительной информации.

См. также sigwait(), sigwaitinfo(), sigtimedwait() и sigpending().

signal.raise_signal(signum)

Отправляет сигнал вызывающему процессу. Ничего не возвращает.

Новое в версии 3.8.

signal.pthread_kill(thread_id, signalnum)

Посылает сигнал signalnum потоку thread_id, другому потоку в том же процессе, что и вызывающий. Целевой поток может выполнять любой код (Python или нет). Однако, если целевой поток выполняет интерпретатор Python, обработчики сигналов Python будут выполнены главным потоком. Следовательно, единственный смысл отправки сигнала конкретному потоку Python – это принудительное завершение работающего системного вызова с ошибкой InterruptedError.

Используйте threading.get_ident() или атрибут ident объектов threading.Thread, чтобы получить подходящее значение для thread_id.

Если signalnum равен 0, сигнал не отправляется, но проверка ошибок по-прежнему выполняется; это можно использовать для проверки, работает ли целевой поток.

Возбуждает событие аудита signal.pthread_kill с аргументами thread_id, signalnum.

Доступность: 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}). Используйте valid_signals() для полной маски, включающей все сигналы.

Например, signal.pthread_sigmask(signal.SIG_BLOCK, []) считывает маску сигналов вызывающего потока.

SIGKILL и SIGSTOP не могут быть заблокированы.

Доступность: Unix. См. man-страницы sigprocmask(3) и pthread_sigmask(3) для получения дополнительной информации.

См. также pause(), sigpending() и sigwait().

Новое в версии 3.3.

signal.setitimer(which, seconds, interval=0.0)

Устанавливает заданный интервальный таймер (один из signal.ITIMER_REAL, signal.ITIMER_VIRTUAL или signal.ITIMER_PROF), указанный параметром which, чтобы он срабатывал через seconds (допускается число с плавающей точкой, в отличие от alarm()) и затем каждые interval секунд (если 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, *, warn_on_full_buffer=True)

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

Возвращается старый fd пробуждения (или -1, если пробуждение через файловый дескриптор не было включено). Если fd равен -1, пробуждение через файловый дескриптор отключается. Если не -1, то fd должен быть неблокирующим. Задача библиотеки – удалить все байты из fd перед повторным вызовом poll или select.

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

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

В первом подходе данные читаются из буфера fd, и значения байтов дают номера сигналов. Это просто, но в редких случаях может возникнуть проблема: обычно fd имеет ограниченный объём буфера, и если слишком много сигналов приходит слишком быстро, буфер может переполниться, и некоторые сигналы могут быть потеряны. Если используется этот подход, следует установить warn_on_full_buffer=True, что, по крайней мере, приведет к выводу предупреждения в stderr при потере сигналов.

Во втором подходе fd пробуждения используется only для пробуждения, а фактические значения байтов игнорируются. В этом случае важно лишь то, пуст буфер fd или нет; полный буфер не свидетельствует о проблеме. Если используется этот подход, следует установить warn_on_full_buffer=False, чтобы пользователи не сбивались с толку ложными предупреждениями.

Изменено в версии 3.5: В Windows функция теперь также поддерживает дескрипторы сокетов.

Изменено в версии 3.7: Добавлен параметр warn_on_full_buffer.

signal.siginterrupt(signalnum, flag)

Изменяет поведение перезапуска системных вызовов: если flag равен False, системные вызовы будут перезапускаться при прерывании сигналом signalnum, в противном случае системные вызовы будут прерваны. Ничего не возвращает.

Доступность: Unix. См. справочную страницу siginterrupt(3) для получения дополнительной информации.

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

signal.signal(signalnum, handler)

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

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

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

В Windows signal() можно вызывать только с SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM или SIGBREAK. В любом другом случае будет возбуждено ValueError. Обратите внимание, что не все системы определяют одинаковый набор имён сигналов; AttributeError будет возбуждено, если имя сигнала не определено как константа уровня модуля SIG*.

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.

Изменено в версии 3.5: Теперь функция повторяется, если прервана сигналом, не входящим в sigset, и обработчик сигнала не возбуждает исключение (см. PEP 475 для обоснования).

signal.sigtimedwait(sigset, timeout)

Как sigwaitinfo(), но принимает дополнительный аргумент timeout, указывающий тайм-аут. Если timeout указан как 0, выполняется опрос. Возвращает None при наступлении тайм-аута.

Доступность: Unix. См. справочную страницу sigtimedwait(2) для получения дополнительной информации.

См. также pause(), sigwait() и sigwaitinfo().

Новое в версии 3.3.

Изменено в версии 3.5: Теперь функция повторяется с пересчитанным timeout, если прервана сигналом, не входящим в sigset, и обработчик сигнала не возбуждает исключение (см. PEP 475 для обоснования).

Пример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)          # Отключить будильник

Примечание о SIGPIPENote on SIGPIPE

Перенаправление вывода программы через конвейер в такие утилиты, как head(1), приводит к отправке сигнала SIGPIPE процессу, когда получатель его стандартного вывода закрывается рано. Это вызывает исключение, подобное BrokenPipeError: [Errno 32] Broken pipe. Для обработки этого случая точку входа следует обернуть для перехвата этого исключения следующим образом:

import os
import sys

def main():
    try:
        # имитировать большой объем вывода (ваш код заменяет этот цикл)
        for x in range(10000):
            print("y")
        # сбросить вывод здесь, чтобы принудительно вызвать SIGPIPE
        # пока внутри этого блока try.
        sys.stdout.flush()
    except BrokenPipeError:
        # Python сбрасывает стандартные потоки при выходе; перенаправьте оставшийся вывод в /dev/null, чтобы избежать ещё одного BrokenPipeError при завершении работы.
        # в devnull, чтобы избежать еще одного BrokenPipeError при завершении
        devnull = os.open(os.devnull, os.O_WRONLY)
        os.dup2(devnull, sys.stdout.fileno())
        sys.exit(1)  # Python завершается с кодом ошибки 1 при EPIPE

if __name__ == '__main__':
    main()

Не устанавливайте обработчик SIGPIPE в SIG_DFL, чтобы избежать BrokenPipeError. Это приведет к неожиданному завершению программы всякий раз, когда соединение через сокет будет прервано во время записи в него.