signal.md
1> **Источник:** https://python-all.ru/3.1/library/signal.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 17.4. `signal` – Установка обработчиков асинхронных событий89Этот модуль предоставляет механизмы для использования обработчиков сигналов в Python. Несколько общих правил работы с сигналами и их обработчиками:1011- Обработчик конкретного сигнала после установки остаётся активным, пока его явно не сбросят (Python эмулирует интерфейс в стиле BSD независимо от базовой реализации), за исключением обработчика `SIGCHLD`, который следует базовой реализации.12- Нет способа временно «блокировать» сигналы в критических секциях (поскольку это поддерживается не во всех разновидностях Unix).13- Хотя с точки зрения пользователя Python обработчики сигналов вызываются асинхронно, они могут возникнуть только между «атомарными» инструкциями интерпретатора Python. Это означает, что сигналы, поступающие во время длительных вычислений, реализованных чисто на C (например, при сопоставлении регулярных выражений с большими объёмами текста), могут быть задержаны на произвольное время.14- Когда сигнал поступает во время операции ввода-вывода, возможно, что после возврата из обработчика сигнала операция ввода-вывода возбудит исключение. Это зависит от семантики прерывания системных вызовов в конкретной Unix-системе.15- Поскольку обработчик сигналов C всегда возвращается, нет особого смысла перехватывать синхронные ошибки, такие как `SIGFPE` или `SIGSEGV`.16- По умолчанию Python устанавливает небольшое количество обработчиков сигналов: `SIGPIPE` игнорируется (поэтому ошибки записи в каналы и сокеты могут быть сообщены как обычные исключения Python), а `SIGINT` преобразуется в исключение [`KeyboardInterrupt`](https://python-all.ru/3.1/library/exceptions.html#KeyboardInterrupt). Все они могут быть переопределены.17- Необходимо соблюдать осторожность при использовании сигналов и потоков в одной программе. Основное, что нужно помнить при одновременной работе с сигналами и потоками: всегда выполняйте операции [`signal()`](https://python-all.ru/3.1/library/signal.html#signal.signal) в главном потоке выполнения. Любой поток может выполнить [`alarm()`](https://python-all.ru/3.1/library/signal.html#signal.alarm), [`getsignal()`](https://python-all.ru/3.1/library/signal.html#signal.getsignal), [`pause()`](https://python-all.ru/3.1/library/signal.html#signal.pause), [`setitimer()`](https://python-all.ru/3.1/library/signal.html#signal.setitimer) или [`getitimer()`](https://python-all.ru/3.1/library/signal.html#signal.getitimer); только главный поток может установить новый обработчик сигнала, и только главный поток будет получать сигналы (это обеспечивается модулем Python `signal`, даже если базовая реализация потоков поддерживает отправку сигналов отдельным потокам). Это означает, что сигналы нельзя использовать как средство межпоточной связи. Вместо этого используйте блокировки.1819Переменные, определённые в модуле `signal`:2021#### `signal.SIG_DFL`2223Это один из двух стандартных вариантов обработки сигналов; он просто выполняет действие по умолчанию для сигнала. Например, на большинстве систем действие по умолчанию для2425`SIGQUIT`2627– сбросить дамп ядра и завершиться, а для2829`SIGCHLD`3031– просто игнорировать его.3233#### `signal.SIG_IGN`3435Это еще один стандартный обработчик сигнала, который просто игнорирует данный сигнал.3637#### `SIG*`3839Все номера сигналов определены символически. Например, сигнал отбоя (hangup) определён как4041`signal.SIGHUP`4243; имена переменных совпадают с именами, используемыми в программах на C, как в4445`<signal.h>`4647. Страница руководства Unix для ‘4849`signal()`5051‘ содержит список существующих сигналов (в некоторых системах это5253*signal(2)*5455, в других список находится в5657*signal(7)*5859). Обратите внимание, что не все системы определяют один и тот же набор имён сигналов; этот модуль определяет только те имена, которые определены системой.6061#### `signal.NSIG`6263На единицу больше номера самого высокого сигнала.6465#### `signal.ITIMER_REAL`6667Уменьшает интервальный таймер в реальном времени и доставляет6869`SIGALRM`7071по истечении времени.7273#### `signal.ITIMER_VIRTUAL`7475Уменьшает интервальный таймер только во время выполнения процесса и отправляет SIGVTALRM по истечении.7677#### `signal.ITIMER_PROF`7879Уменьшает интервальный таймер как при выполнении процесса, так и при выполнении системой от имени процесса. В паре с ITIMER\_VIRTUAL этот таймер обычно используется для профилирования времени, затраченного приложением в пользовательском и ядерном пространстве. SIGPROF доставляется по истечении времени.8081Модуль `signal` определяет одно исключение:8283#### `exception signal.ItimerError`8485Возбуждается для сообщения об ошибке в реализации8687[`setitimer()`](https://python-all.ru/3.1/library/signal.html#signal.setitimer)8889или9091[`getitimer()`](https://python-all.ru/3.1/library/signal.html#signal.getitimer)9293. Ожидайте эту ошибку, если в9495[`setitimer()`](https://python-all.ru/3.1/library/signal.html#signal.setitimer)9697передан недопустимый интервальный таймер или отрицательное время. Эта ошибка является подтипом9899[`IOError`](https://python-all.ru/3.1/library/exceptions.html#IOError)100101.102103Модуль `signal` определяет следующие функции:104105#### `signal.alarm(time)`106107Если108109*time*110111не равно нулю, эта функция запрашивает отправку сигнала112113`SIGALRM`114115процессу через116117*time*118119секунд. Любой ранее запланированный сигнал отменяется (в любой момент времени может быть запланирован только один сигнал). Возвращаемое значение – количество секунд до момента, когда должен был быть доставлен любой ранее установленный сигнал. Если120121*time*122123равно нулю, сигнал не планируется, а любой запланированный отменяется. Если возвращаемое значение равно нулю, сигнал в данный момент не запланирован. (См. man-страницу Unix124125*alarm(2)*126127.) Доступность: Unix.128129#### `signal.getsignal(signalnum)`130131Возвращает текущий обработчик сигнала для сигнала132133*signalnum*134135. Возвращаемое значение может быть вызываемым объектом Python или одним из специальных значений:136137[`signal.SIG_IGN`](https://python-all.ru/3.1/library/signal.html#signal.SIG_IGN)138139,140141[`signal.SIG_DFL`](https://python-all.ru/3.1/library/signal.html#signal.SIG_DFL)142143или144145[`None`](https://python-all.ru/3.1/library/constants.html#None)146147. Здесь148149[`signal.SIG_IGN`](https://python-all.ru/3.1/library/signal.html#signal.SIG_IGN)150151означает, что сигнал ранее игнорировался,152153[`signal.SIG_DFL`](https://python-all.ru/3.1/library/signal.html#signal.SIG_DFL)154155означает, что ранее использовался способ обработки сигнала по умолчанию, а156157`None`158159означает, что предыдущий обработчик сигнала не был установлен из Python.160161#### `signal.pause()`162163Заставляет процесс спать до получения сигнала; затем будет вызван соответствующий обработчик. Ничего не возвращает. Недоступно в Windows. (См. страницу руководства Unix164165*signal(2)*166167.)168169#### `signal.setitimer(which, seconds[, interval])`170171Устанавливает заданный интервальный таймер (один из [`signal.ITIMER_REAL`](https://python-all.ru/3.1/library/signal.html#signal.ITIMER_REAL), [`signal.ITIMER_VIRTUAL`](https://python-all.ru/3.1/library/signal.html#signal.ITIMER_VIRTUAL) или [`signal.ITIMER_PROF`](https://python-all.ru/3.1/library/signal.html#signal.ITIMER_PROF)), указанный *which*, чтобы он сработал через *seconds* (принимается число с плавающей запятой, в отличие от [`alarm()`](https://python-all.ru/3.1/library/signal.html#signal.alarm)) и после этого каждые *interval* секунд. Интервальный таймер, указанный *which*, можно сбросить, установив seconds в ноль.172173Когда интервальный таймер срабатывает, процессу отправляется сигнал. Отправляемый сигнал зависит от используемого таймера; [`signal.ITIMER_REAL`](https://python-all.ru/3.1/library/signal.html#signal.ITIMER_REAL) доставляет `SIGALRM`, [`signal.ITIMER_VIRTUAL`](https://python-all.ru/3.1/library/signal.html#signal.ITIMER_VIRTUAL) отправляет `SIGVTALRM`, а [`signal.ITIMER_PROF`](https://python-all.ru/3.1/library/signal.html#signal.ITIMER_PROF) доставляет `SIGPROF`.174175Старые значения возвращаются в виде кортежа: (delay, interval).176177Попытка передать недопустимый интервальный таймер вызовет [`ItimerError`](https://python-all.ru/3.1/library/signal.html#signal.ItimerError). Доступность: Unix.178179#### `signal.getitimer(which)`180181Возвращает текущее значение указанного интервального таймера, заданного через182183*which*184185. Доступность: Unix.186187#### `signal.set_wakeup_fd(fd)`188189Устанавливает fd пробуждения в *fd*. Когда получен сигнал, в fd записывается один `'\0'` байт. Это может использоваться библиотекой для пробуждения вызова poll или select, чтобы сигнал был полностью обработан.190191Возвращается старый дескриптор пробуждения. *fd* должен быть неблокирующим. Библиотека должна удалить все байты перед повторным вызовом poll или select.192193Когда потоки включены, эту функцию можно вызывать только из основного потока; попытка вызова из других потоков приведёт к возникновению исключения [`ValueError`](https://python-all.ru/3.1/library/exceptions.html#ValueError).194195#### `signal.siginterrupt(signalnum, flag)`196197Изменяет поведение перезапуска системных вызовов: если *flag* равно [`False`](https://python-all.ru/3.1/library/constants.html#False), системные вызовы будут перезапущены при прерывании сигналом *signalnum*, в противном случае системные вызовы будут прерваны. Ничего не возвращает. Доступность: Unix (см. man-страницу *siginterrupt(3)* для получения дополнительной информации).198199Обратите внимание, что установка обработчика сигнала с помощью [`signal()`](https://python-all.ru/3.1/library/signal.html#signal.signal) сбросит поведение перезапуска на прерываемое, неявно вызывая `siginterrupt()` со значением *flag*, равным true, для данного сигнала.200201#### `signal.signal(signalnum, handler)`202203Устанавливает обработчик сигнала *signalnum* как функцию *handler*. *handler* может быть вызываемым объектом Python, принимающим два аргумента (см. ниже), или одним из специальных значений [`signal.SIG_IGN`](https://python-all.ru/3.1/library/signal.html#signal.SIG_IGN) или [`signal.SIG_DFL`](https://python-all.ru/3.1/library/signal.html#signal.SIG_DFL). Ранее установленный обработчик сигнала будет возвращён (см. описание [`getsignal()`](https://python-all.ru/3.1/library/signal.html#signal.getsignal) выше). (См. страницу руководства Unix *signal(2)*.)204205Когда потоки включены, эту функцию можно вызывать только из основного потока; попытка вызова из других потоков приведёт к возникновению исключения [`ValueError`](https://python-all.ru/3.1/library/exceptions.html#ValueError).206207*handler* вызывается с двумя аргументами: номером сигнала и текущим стековым кадром (`None` или объект кадра; описание объектов кадра см. в [*описании иерархии типов*](https://python-all.ru/3.1/reference/datamodel.html#frame-objects) или в описаниях атрибутов в модуле [`inspect`](https://python-all.ru/3.1/library/inspect.html#module-inspect)).208209В Windows [`signal()`](https://python-all.ru/3.1/library/signal.html#signal.signal) можно вызывать только с `SIGABRT`, `SIGFPE`, `SIGILL`, `SIGINT`, `SIGSEGV` или `SIGTERM`. В любом другом случае будет вызвано [`ValueError`](https://python-all.ru/3.1/library/exceptions.html#ValueError).210211## 17.4.1. Пример212213Вот минимальный пример программы. В ней используется функция [`alarm()`](https://python-all.ru/3.1/library/signal.html#signal.alarm) для ограничения времени ожидания открытия файла; это полезно, если файл относится к последовательному устройству, которое может быть выключено, и обычно это приводит к тому, что [`os.open()`](https://python-all.ru/3.1/library/os.html#os.open) зависает на неопределённый срок. Решение – установить 5-секундный будильник перед открытием файла; если операция займёт слишком много времени, будет отправлен сигнал будильника, и обработчик вызовет исключение.214215```python216import signal, os217218def handler(signum, frame):219 print('Signal handler called with signal', signum)220 raise IOError("Couldn't open device!")221222# Установить обработчик сигнала и 5-секундный будильник223signal.signal(signal.SIGALRM, handler)224signal.alarm(5)225226# Этот вызов open() может зависнуть навсегда227fd = os.open('/dev/ttyS0', os.O_RDWR)228229signal.alarm(0) # Отключить будильник230```231