Python - 捕获所有信号

发布于 2024-08-19 12:50:58 字数 219 浏览 6 评论 0原文

在Linux下的python 2.6中,我可以使用以下命令来处理TERM信号:

import signal
def handleSigTERM():
    shutdown()
signal.signal(signal.SIGTERM, handleSigTERM)    

除了一次设置一个信号之外,还有什么方法可以为进程接收到的所有信号设置处理程序?

In python 2.6 under Linux, I can use the following to handle a TERM signal:

import signal
def handleSigTERM():
    shutdown()
signal.signal(signal.SIGTERM, handleSigTERM)    

Is there any way to setup a handler for all signals received by the process, other than just setting them up one-at-a-time?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

马蹄踏│碎落叶 2024-08-26 12:50:59

适用于 Windows 10 和 Python 3.7:

import signal
import time

def sighandler(signal,frame):
    print("signal",sig,frame)
    return

catchable_sigs = set(signal.Signals)
for sig in catchable_sigs:
    try:
        signal.signal(sig, sighandler)
        print("Setting ",sig)
        print ("value {}".format(sig))
    except (ValueError, OSError, RuntimeError) as m:
        print("Skipping ",sig)
        print ("Value {}".format(sig))


# press some keys or issue kill
x = 0
while x < 5:
    time.sleep(4)
    x += 1

结果:

Skipping  Signals.CTRL_C_EVENT
Value 0
Skipping  Signals.CTRL_BREAK_EVENT
Value 1
Setting  Signals.SIGINT
value 2
Setting  Signals.SIGILL
value 4
Setting  Signals.SIGFPE
value 8
Setting  Signals.SIGSEGV
value 11
Setting  Signals.SIGTERM
value 15
Setting  Signals.SIGBREAK
value 21
Setting  Signals.SIGABRT
value 22

Works on Windows 10 and Python 3.7:

import signal
import time

def sighandler(signal,frame):
    print("signal",sig,frame)
    return

catchable_sigs = set(signal.Signals)
for sig in catchable_sigs:
    try:
        signal.signal(sig, sighandler)
        print("Setting ",sig)
        print ("value {}".format(sig))
    except (ValueError, OSError, RuntimeError) as m:
        print("Skipping ",sig)
        print ("Value {}".format(sig))


# press some keys or issue kill
x = 0
while x < 5:
    time.sleep(4)
    x += 1

Results:

Skipping  Signals.CTRL_C_EVENT
Value 0
Skipping  Signals.CTRL_BREAK_EVENT
Value 1
Setting  Signals.SIGINT
value 2
Setting  Signals.SIGILL
value 4
Setting  Signals.SIGFPE
value 8
Setting  Signals.SIGSEGV
value 11
Setting  Signals.SIGTERM
value 15
Setting  Signals.SIGBREAK
value 21
Setting  Signals.SIGABRT
value 22
酒绊 2024-08-26 12:50:59

这是一种 2/3 兼容的方法,它不像其他方法那样有那么多陷阱:

from itertools import count
import signal

def set_all_signal_signals(handler):
    """Set all signals to a particular handler."""
    for signalnum in count(1):
        try:
            signal.signal(signalnum, handler)
            print("set {}".format(signalnum))
        except (OSError, RuntimeError):
            # Invalid argument such as signals that can't be blocked
            pass
        except ValueError:
            # Signal out of range
            break

由于 signalnum 只是一个数字,因此迭代 1 到超出范围,将信号设置为特定句柄。

Here's a 2/3 compatible way which doesn't have as many pitfalls as the others:

from itertools import count
import signal

def set_all_signal_signals(handler):
    """Set all signals to a particular handler."""
    for signalnum in count(1):
        try:
            signal.signal(signalnum, handler)
            print("set {}".format(signalnum))
        except (OSError, RuntimeError):
            # Invalid argument such as signals that can't be blocked
            pass
        except ValueError:
            # Signal out of range
            break

Since signalnum is just a number, iterate over 1 to out of range setting the signal to a particular handle.

残花月 2024-08-26 12:50:59

在Python3.8中,我们有了一个新函数 signal.valid_signals() https://docs.python.org/3/library/signal.html#signal.valid_signals

import signal
for sig in signal.valid_signals():
    print(f"{sig:2d}",sig)

In Python3.8 we've got a new function signal.valid_signals() https://docs.python.org/3/library/signal.html#signal.valid_signals

import signal
for sig in signal.valid_signals():
    print(f"{sig:2d}",sig)
君勿笑 2024-08-26 12:50:59

对于Python 3:

for sig in signal.Signals:
    try:
        signal.signal(sig, sighandler)
    except OSError:
        print('Skipping', sig)

For Python 3:

for sig in signal.Signals:
    try:
        signal.signal(sig, sighandler)
    except OSError:
        print('Skipping', sig)
放我走吧 2024-08-26 12:50:59

该代码在当前版本的 python 中不起作用。有许多以 SIG 开头且具有相同值的变量。例如,SIGHUP 和 SIG_UNBLOCK 都是 1。我能想到的获取实际信号列表的唯一方法就是自己制作。

from signal import *    
signals = {
        SIGABRT: 'SIGABRT',
        SIGALRM: 'SIGALRM',
        SIGBUS: 'SIGBUS',
        SIGCHLD: 'SIGCHLD',
        SIGCONT: 'SIGCONT',
        SIGFPE: 'SIGFPE',
        SIGHUP: 'SIGHUP',
        SIGILL: 'SIGILL',
        SIGINT: 'SIGINT',
        SIGPIPE: 'SIGPIPE',
        SIGPOLL: 'SIGPOLL',
        SIGPROF: 'SIGPROF',
        SIGQUIT: 'SIGQUIT',
        SIGSEGV: 'SIGSEGV',
        SIGSYS: 'SIGSYS',
        SIGTERM: 'SIGTERM',
        SIGTRAP: 'SIGTRAP',
        SIGTSTP: 'SIGTSTP',
        SIGTTIN: 'SIGTTIN',
        SIGTTOU: 'SIGTTOU',
        SIGURG: 'SIGURG',
        SIGUSR1: 'SIGUSR1',
        SIGUSR2: 'SIGUSR2',
        SIGVTALRM: 'SIGVTALRM',
        SIGXCPU: 'SIGXCPU',
        SIGXFSZ: 'SIGXFSZ',
        }

for num in signals:
    signal(num, h)

That code won't work in the current version of python. There are many variables starting with SIG with the same value. For instance, SIGHUP and SIG_UNBLOCK are both 1. The only way I could think of to get a list of actual signals was to just make it myself.

from signal import *    
signals = {
        SIGABRT: 'SIGABRT',
        SIGALRM: 'SIGALRM',
        SIGBUS: 'SIGBUS',
        SIGCHLD: 'SIGCHLD',
        SIGCONT: 'SIGCONT',
        SIGFPE: 'SIGFPE',
        SIGHUP: 'SIGHUP',
        SIGILL: 'SIGILL',
        SIGINT: 'SIGINT',
        SIGPIPE: 'SIGPIPE',
        SIGPOLL: 'SIGPOLL',
        SIGPROF: 'SIGPROF',
        SIGQUIT: 'SIGQUIT',
        SIGSEGV: 'SIGSEGV',
        SIGSYS: 'SIGSYS',
        SIGTERM: 'SIGTERM',
        SIGTRAP: 'SIGTRAP',
        SIGTSTP: 'SIGTSTP',
        SIGTTIN: 'SIGTTIN',
        SIGTTOU: 'SIGTTOU',
        SIGURG: 'SIGURG',
        SIGUSR1: 'SIGUSR1',
        SIGUSR2: 'SIGUSR2',
        SIGVTALRM: 'SIGVTALRM',
        SIGXCPU: 'SIGXCPU',
        SIGXFSZ: 'SIGXFSZ',
        }

for num in signals:
    signal(num, h)
静若繁花 2024-08-26 12:50:58

从 Python 3.5 开始,信号常量定义为枚举 ,实现更好的方法:

import signal

catchable_sigs = set(signal.Signals) - {signal.SIGKILL, signal.SIGSTOP}
for sig in catchable_sigs:
    signal.signal(sig, print)  # Substitute handler of choice for `print`

As of Python 3.5, the signal constants are defined as an enum, enabling a nicer approach:

import signal

catchable_sigs = set(signal.Signals) - {signal.SIGKILL, signal.SIGSTOP}
for sig in catchable_sigs:
    signal.signal(sig, print)  # Substitute handler of choice for `print`
想念有你 2024-08-26 12:50:58

您只需循环信号模块中的信号并进行设置即可。

for i in [x for x in dir(signal) if x.startswith("SIG")]:
  try:
    signum = getattr(signal,i)
    signal.signal(signum,sighandler)
  except (OSError, RuntimeError) as m: #OSError for Python3, RuntimeError for 2
    print ("Skipping {}".format(i))

You could just loop through the signals in the signal module and set them up.

for i in [x for x in dir(signal) if x.startswith("SIG")]:
  try:
    signum = getattr(signal,i)
    signal.signal(signum,sighandler)
  except (OSError, RuntimeError) as m: #OSError for Python3, RuntimeError for 2
    print ("Skipping {}".format(i))
紫罗兰の梦幻 2024-08-26 12:50:58

如果你想摆脱try,只需忽略无法捕获的信号即可。

#!/usr/bin/env python
# https://stackoverflow.com/questions/2148888/python-trap-all-signals
import os
import sys
import time
import signal

SIGNALS_TO_NAMES_DICT = dict((getattr(signal, n), n) \
    for n in dir(signal) if n.startswith('SIG') and '_' not in n )


def receive_signal(signum, stack):
    if signum in [1,2,3,15]:
        print 'Caught signal %s (%s), exiting.' % (SIGNALS_TO_NAMES_DICT[signum], str(signum))
        sys.exit()
    else:
        print 'Caught signal %s (%s), ignoring.' % (SIGNALS_TO_NAMES_DICT[signum], str(signum))

def main():
    uncatchable = ['SIG_DFL','SIGSTOP','SIGKILL']
    for i in [x for x in dir(signal) if x.startswith("SIG")]:
        if not i in uncatchable:
            signum = getattr(signal,i)
            signal.signal(signum,receive_signal)
    print('My PID: %s' % os.getpid())
    while True:
        time.sleep(1)
main()

If you want to get rid of the try, just ignore signals that cannot be caught.

#!/usr/bin/env python
# https://stackoverflow.com/questions/2148888/python-trap-all-signals
import os
import sys
import time
import signal

SIGNALS_TO_NAMES_DICT = dict((getattr(signal, n), n) \
    for n in dir(signal) if n.startswith('SIG') and '_' not in n )


def receive_signal(signum, stack):
    if signum in [1,2,3,15]:
        print 'Caught signal %s (%s), exiting.' % (SIGNALS_TO_NAMES_DICT[signum], str(signum))
        sys.exit()
    else:
        print 'Caught signal %s (%s), ignoring.' % (SIGNALS_TO_NAMES_DICT[signum], str(signum))

def main():
    uncatchable = ['SIG_DFL','SIGSTOP','SIGKILL']
    for i in [x for x in dir(signal) if x.startswith("SIG")]:
        if not i in uncatchable:
            signum = getattr(signal,i)
            signal.signal(signum,receive_signal)
    print('My PID: %s' % os.getpid())
    while True:
        time.sleep(1)
main()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文