Адрес столбца:Один модуль Python в неделю
В то же время, вы также можете обратить внимание на мой публичный аккаунт WeChat.AlwaysBeta, вас ждет еще больше захватывающего контента.
Сигналы — это распространенный метод межпроцессного взаимодействия (IPC) в системах Unix, таких как те, которые мы часто используем.kill -9 pid
,здесь-9
Соответствует сигналу SIGKILL, 9 — номер сигнала, а SIGKILL — его имя. Поскольку реализация разных версий *nux будет отличаться, обратитесь к системному API за подробностями, вы можете использоватьman 7 signal
Просмотрите все определения сигналов.
Итак, каковы сценарии использования сигнала? По сравнению с другими методами межпроцессного взаимодействия (такими как конвейеры, разделяемая память и т. д.) информация, которую могут передавать сигналы, является относительно грубой, всего лишь целым числом. Но именно из-за небольшого объема передаваемой информации сигнал также проще в управлении и использовании, и его можно использовать для задач, связанных с управлением системой. Например, уведомить о завершении процесса, прервать или возобновить. Каждый сигнал представлен целочисленным константным макросом, начинающимся с SIG, например SIGCHLD, SIGINT и т. д.
получить сигнал
Модуль signal используется в Python для обработки операций, связанных с сигналами, которые определяются следующим образом:
signal.signal(signalnum, handler)
signalnum — это сигнал, а handler — это функция обработки сигнала. Процессы могут игнорировать сигналы, выполнять действия по умолчанию и настраивать действия. Когда обработчиком является signal.SIG_IGN, сигнал игнорируется, когда обработчиком является singal.SIG_DFL, процесс выполняет действие по умолчанию (по умолчанию), когда обработчик является именем функции, процесс выполняет действие, определенное в функции.
Напишите небольшую программу для обработкиctrl+c
события иSIGHUP
, то есть сигналы 1 и 2.
#coding:utf-8
import signal
import time
import sys
import os
def handle_int(sig, frame):
print "get signal: %s, I will quit"%sig
sys.exit(0)
def handle_hup(sig, frame):
print "get signal: %s"%sig
if __name__ == "__main__":
signal.signal(2, handle_int)
signal.signal(1, handle_hup)
print "My pid is %s"%os.getpid()
while True:
time.sleep(3)
Протестируем, сначала запускаем программу (по распечатанному pid), входим в другом окнеkill -1 21838
иkill -HUP 21838
, наконец, используйтеctrl+c
выключить приложение. Вывод программы следующий:
# python recv_signal.py
My pid is 21838
get signal: 1
get signal: 1
^Cget signal: 2, I will quit
Давайте посмотрим на другую функцию, чтобы лучше понять сигнал:
signal.getsignal(signalnum)
Согласно обработчику, соответствующему сигналу, возвращаемому signalnum, это может быть вызываемый объект Python илиsignal.SIG_IGN
(имеется в виду игнорировать),signal.SIG_DFL
(поведение по умолчанию уже используется) илиNone
(Обработчик Python еще не определен).
См. следующий пример, чтобы получить номер и имя сигнала, определенные в сигнале, и его обработчик.
#coding:utf-8
import signal
def handle_hup(sig, frame):
print "get signal: %s"%sig
signal.signal(1, handle_hup)
if __name__ == "__main__":
ign = signal.SIG_IGN
dfl = signal.SIG_DFL
print "SIG_IGN", ign
print "SIG_DFL", dfl
print "*"*40
for name in dir(signal):
if name[:3] == "SIG" and name[3] != "_":
signum = getattr(signal, name)
gsig = signal.getsignal(signum)
print name, signum, gsig
Результат запуска: Вы можете видеть, что большинство сигналов имеют поведение по умолчанию.
SIG_IGN 1
SIG_DFL 0
****************************************
SIGABRT 6 0
SIGALRM 14 0
SIGBUS 10 0
SIGCHLD 20 0
SIGCONT 19 0
SIGEMT 7 0
SIGFPE 8 0
SIGHUP 1 <function handle_hup at 0x109371c80>
SIGILL 4 0
SIGINFO 29 0
SIGINT 2 <built-in function default_int_handler>
SIGIO 23 0
SIGIOT 6 0
SIGKILL 9 None
SIGPIPE 13 1
SIGPROF 27 0
SIGQUIT 3 0
SIGSEGV 11 0
SIGSTOP 17 None
SIGSYS 12 0
SIGTERM 15 0
SIGTRAP 5 0
SIGTSTP 18 0
SIGTTIN 21 0
SIGTTOU 22 0
SIGURG 16 0
SIGUSR1 30 0
SIGUSR2 31 0
SIGVTALRM 26 0
SIGWINCH 28 0
SIGXCPU 24 0
SIGXFSZ 25 1
Несколько часто используемых сигналов:
Нумерация | название | эффект |
---|---|---|
1 | SIGHUP | Терминал зависает или завершает процесс. Действие по умолчанию — завершить процесс |
2 | SIGINT | прерывание клавиатуры<ctrl+c> Часто используется. Действие по умолчанию — завершить процесс |
3 | SIGQUIT | Нажата клавиша выхода на клавиатуре. Обычно используется для ответа<ctrl+d> . Действие по умолчанию завершает процесс |
9 | SIGKILL | Принудительно выйти. часто используется в оболочке |
14 | SIGALRM | Таймер истекает, по умолчанию процесс завершается |
15 | SIGTERM | Сигнал окончания программы, программа, как правило, очищает состояние и завершает работу, мы обычно говорим: изящный выход. |
послать сигнал
Ядром пакета signal является установка функции обработчика сигнала. Кромеsignal.alarm()
Нет никакой другой функции отправки сигналов, кроме отправки сигналов самому себе. Но в пакете os есть функции, похожие на команду kill в Linux, а именно:
os.kill(pid, sid)
os.killpg(pgid, sid)
Сигналы отправляются процессам и группам процессов соответственно. sid — это целое число, соответствующее сигналу или singal.SIG*.
Периодически выдавать сигнал SIGALRM
Он используется для отправки сигнала SIGALRM самому процессу через определенное время, что полезно, чтобы избежать блокировки операций ввода-вывода или других системных вызовов на неопределенный срок.
import signal
import time
def receive_alarm(signum, stack):
print('Alarm :', time.ctime())
# Call receive_alarm in 2 seconds
signal.signal(signal.SIGALRM, receive_alarm)
signal.alarm(2)
print('Before:', time.ctime())
time.sleep(4)
print('After :', time.ctime())
# output
# Before: Sat Apr 22 14:48:57 2017
# Alarm : Sat Apr 22 14:48:59 2017
# After : Sat Apr 22 14:49:01 2017
В этом примере вызовsleep()
прерывается, но продолжается после обработки сигнала, поэтомуsleep()
Сообщение, напечатанное после возврата, показывает, что программа выполняется до тех пор, пока длится спящий режим.
игнорировать сигнал
Чтобы игнорировать сигнал, зарегистрируйте SIG_IGN в качестве обработчика.
В следующем примере регистрируются две программы, SIGINT и SIGUSR1, а затем используетсяsignal.pause()
Ожидание получения сигнала.
import signal
import os
import time
def do_exit(sig, stack):
raise SystemExit('Exiting')
signal.signal(signal.SIGINT, signal.SIG_IGN)
signal.signal(signal.SIGUSR1, do_exit)
print('My PID:', os.getpid())
signal.pause()
# output
# My PID: 72598
# ^C^C^C^CExiting
Обычно SIGINT (когда пользователь нажимаетCtrl-C
сигнал, отправленный в программу оболочкой) подниметKeyboardInterrupt
. Этот пример просто игнорирует SIGINT, когда видит его. каждый на выходе^C
Указывает на попытку завершить скрипт с терминала.
использовать с другого терминалаkill -USR1 72598
Выйдите из сценария.
Сигналы и потоки
При использовании сигналов в многопоточной среде только основной поток может установить обработчик сигнала, и только он может получить сигнал.Давайте рассмотрим пример, чтобы увидеть эффект, ожидание сигнала в одном потоке и отправка сигнала из другой ветки.
#coding:utf-8
#orangleliu py2.7
#thread_signal.py
import signal
import threading
import os
import time
def usr1_handler(num, frame):
print "received signal %s %s"%(num, threading.currentThread())
signal.signal(signal.SIGUSR1, usr1_handler)
def thread_get_signal():
#如果在子线程中设置signal的handler 会报错
#ValueError: signal only works in main thread
#signal.signal(signal.SIGUSR2, usr1_handler)
print "waiting for signal in", threading.currentThread()
#sleep 进程直到接收到信号
signal.pause()
print "waiting done"
receiver = threading.Thread(target=thread_get_signal, name="receiver")
receiver.start()
time.sleep(0.1)
def send_signal():
print "sending signal in ", threading.currentThread()
os.kill(os.getpid(), signal.SIGUSR1)
sender = threading.Thread(target=send_signal, name="sender")
sender.start()
sender.join()
print 'pid', os.getpid()
# 这里是为了让程序结束,唤醒 pause
signal.alarm(2)
receiver.join()
# output
# waiting for signal in <Thread(receiver, started 123145306509312)>
# sending signal in <Thread(sender, started 123145310715904)>
# received signal 30 <_MainThread(MainThread, started 140735138967552)>
# pid 23188
# [1] 23188 alarm python thread_signal.py
Модуль сигналов Python требует, чтобы все обработчики были зарегистрированы в основном потоке, даже если базовая платформа поддерживает программирование смешанных потоков и сигналов. Даже если принимающий поток вызываетsignal.pause()
, но сигнал по-прежнему не принимается. в конце кодаsignal.alarm(2)
это разбудить принимающий потокpause()
, иначе принимающий поток никогда не завершится.
Хотя сигналы тревоги могут быть установлены в любом потоке, они могут быть получены только в основном потоке.
import signal
import time
import threading
def signal_handler(num, stack):
print(time.ctime(), 'Alarm in',
threading.currentThread().name)
signal.signal(signal.SIGALRM, signal_handler)
def use_alarm():
t_name = threading.currentThread().name
print(time.ctime(), 'Setting alarm in', t_name)
signal.alarm(1)
print(time.ctime(), 'Sleeping in', t_name)
time.sleep(3)
print(time.ctime(), 'Done with sleep in', t_name)
# Start a thread that will not receive the signal
alarm_thread = threading.Thread(
target=use_alarm,
name='alarm_thread',
)
alarm_thread.start()
time.sleep(0.1)
# Wait for the thread to see the signal (not going to happen!)
print(time.ctime(), 'Waiting for', alarm_thread.name)
alarm_thread.join()
print(time.ctime(), 'Exiting normally')
# output
# Sat Apr 22 14:49:01 2017 Setting alarm in alarm_thread
# Sat Apr 22 14:49:01 2017 Sleeping in alarm_thread
# Sat Apr 22 14:49:01 2017 Waiting for alarm_thread
# Sat Apr 22 14:49:02 2017 Alarm in MainThread
# Sat Apr 22 14:49:04 2017 Done with sleep in alarm_thread
# Sat Apr 22 14:49:04 2017 Exiting normally
тревога не прерываетсяuse_alarm()
серединаsleep
.
Связанные документы:
Дешевый Мо Corruption.com/3/signal/in…