Python之signal模块的使用


常用的信号值如下:

信号值                    事件                                        处理方式
    SIGHUP                    终止进程                                    终端线路挂断
    SIGINT                    终止进程                                    中断进程
    SIGQUIT                    "建立CORE文件终止进程,并且生成core文件"    
    SIGILL                    建立CORE文件                                非法指令
    SIGTRAP                    建立CORE文件                                跟踪自陷
    SIGBUS                    建立CORE文件                                总线错误
    SIGSEGV                    建立CORE文件                                段非法错误
    SIGFPE                    建立CORE文件                                浮点异常
    SIGIOT                    建立CORE文件                                执行I/O自陷
    SIGKILL                    终止进程                                    杀死进程
    SIGPIPE                    终止进程                                    向一个没有读进程的管道写数据
    SIGALARM                终止进程                                    计时器到时
    SIGTERM                    终止进程                                    软件终止信号
    SIGSTOP                    停止进程                                    非终端来的停止信号
    SIGTSTP                    停止进程                                    终端来的停止信号
    SIGCONT                    忽略信号                                    继续执行一个停止的进程
    SIGURG                    忽略信号                                    I/O紧急信号
    SIGIO                    忽略信号                                    描述符上可以进行I/O
    SIGCHLD                    忽略信号                                    当子进程停止或退出时通知父进程
    SIGTTOU                    停止进程                                    后台进程写终端
    SIGTTIN                    停止进程                                    后台进程读终端
    SIGXGPU                    终止进程                                    CPU时限超时
    SIGXFSZ                    终止进程                                    文件长度过长
    SIGWINCH                忽略信号                                    窗口大小发生变化
    SIGPROF                    终止进程                                    统计分布图用计时器到时
    SIGUSR1                    终止进程                                    用户定义信号1
    SIGUSR2                    终止进程                                    用户定义信号2
    SIGVTALRM                终止进程                                    虚拟计时器到时

1、接收信号绑定处理对应的事件

#!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import signal
    import os
    import time

    def receive_signal(signum, stack):
        """用于接收信号,对signum的值区分信号,实现不同的信号做对应的处理"""
        print('接收的signum', signum)

    #注册处理信号的事件,此处对用户定义信号1、用户定义信号2,绑定事件
    signal.signal(signal.SIGUSR1, receive_signal)
    signal.signal(signal.SIGUSR2, receive_signal)

    print('我的PID: %s' % os.getpid())

    #开启循环监听信号
    while True:
        print('Waiting...')
        time.sleep(3)

signal_signal.py

运行效果

#终端1
    [root@ mnt]# python3 signal_signal.py 
    我的PID: 14718
    Waiting... #==>每3秒打印一次
    Waiting...
    Waiting...
    接收的signum 10 #==>接收到kill -USR1 14718的命令,作出的动作
    Waiting...
    接收的signum 12 #==>接收到kill -USR2 14718的命令,作出的动作
    Waiting...
    Waiting...
    Traceback (most recent call last): #==>接收到kill -INT 14718命令的动作
      File "signal_signal.py", line 22, in <module>
        time.sleep(3)
    KeyboardInterrupt

    #终端2
    [root@ ~]# kill -USR1 14718
    [root@ ~]# kill -USR2 14718
    [root@ ~]# kill -INT 14718

2、获取已注册信号处理器事件

#!/usr/bin/env python
    # -*- coding: utf-8 -*-

    import signal

    def alarm_received(n, stack):
        return

    signal.signal(signal.SIGALRM, alarm_received)

    # 字典格式:{<Signals.SIGABRT: 6>: 'SIGIOT', <Signals.SIGALRM: 14>: 'SIGALRM'...}
    signals_to_names = {
        getattr(signal, n): n
        for n in dir(signal) if n.startswith('SIG') and '_' not in n
    }

    for s, name in sorted(signals_to_names.items()):
        handler = signal.getsignal(s)  # 获取信号的有没有绑定信号事件
        if handler is signal.SIG_DFL:  # 判断有没有绑定信号事件,没有的话,设置为SIG_DFL或SIG_IGN
            handler = 'SIG_DFL'
        elif handler is signal.SIG_IGN:
            handler = 'SIG_IGN'
        print('{:<10} ({:2d}):'.format(name, s), handler)

signal_getsignal.py

运行效果

[root@ mnt]# python3 signal_getsignal.py 
    SIGHUP     ( 1): SIG_DFL
    SIGINT     ( 2): <built-in function default_int_handler>
    SIGQUIT    ( 3): SIG_DFL
    SIGILL     ( 4): SIG_DFL
    SIGTRAP    ( 5): SIG_DFL
    SIGIOT     ( 6): SIG_DFL
    SIGBUS     ( 7): SIG_DFL
    SIGFPE     ( 8): SIG_DFL
    SIGKILL    ( 9): SIG_DFL
    SIGUSR1    (10): SIG_DFL
    SIGSEGV    (11): SIG_DFL
    SIGUSR2    (12): SIG_DFL
    SIGPIPE    (13): SIG_IGN
    SIGALRM    (14): _**< function alarm_received at 0x7f2bc1002e18>**_
    SIGTERM    (15): SIG_DFL
    SIGCLD     (17): SIG_DFL
    SIGCONT    (18): SIG_DFL
    SIGSTOP    (19): SIG_DFL
    SIGTSTP    (20): SIG_DFL
    SIGTTIN    (21): SIG_DFL
    SIGTTOU    (22): SIG_DFL
    SIGURG     (23): SIG_DFL
    SIGXCPU    (24): SIG_DFL
    SIGXFSZ    (25): SIG_IGN
    SIGVTALRM  (26): SIG_DFL
    SIGPROF    (27): SIG_DFL
    SIGWINCH   (28): SIG_DFL
    SIGPOLL    (29): SIG_DFL
    SIGPWR     (30): SIG_DFL
    SIGSYS     (31): SIG_DFL
    SIGRTMIN   (34): SIG_DFL
    SIGRTMAX   (64): SIG_DFL

3、发送信号

#!/usr/bin/env python
    # -*- coding: utf-8 -*-

    import os
    import signal
    import sys
    os.kill(int(sys.argv[1]),signal.SIGUSR1)

signal_send.py

4、告警信号

import signal
    import time

    def receive_alarm(signum, stack):
        print('告警时间 :', time.ctime())

    signal.signal(signal.SIGALRM, receive_alarm)
    signal.alarm(2) #2秒后调用SIGALRM信号的事件

    print('之前运行时间:', time.ctime())
    time.sleep(4)
    print('之后运行时间: :', time.ctime())

signal_alarm.py

运行效果

[root@ mnt]# python3 signal_alarm.py 
    之前运行时间: Thu Dec  5 16:02:11 2019
    告警时间 : Thu Dec  5 16:02:13 2019
    之后运行时间: : Thu Dec  5 16:02:15 2019

5、怱略信号

import signal
    import os

    def do_exit(sig, stack):
        raise SystemExit('Exiting')  # 退出程序并打印显示

    # 注册使用SIGINT发送信号,做忽略处理
    signal.signal(signal.SIGINT, signal.SIG_IGN)

    # 注册使用SIGUSR1发送信号,交给do_exit函数处理
    signal.signal(signal.SIGUSR1, do_exit)

    print('我的PID: %s' % os.getpid())

    signal.pause()  # 暂停

signal_ignore.py

运行效果

#终端1
    #Ctrl+C,失效,因为Ctrl+C发送的信号是SIGINT,已经被怱略
    [root@ mnt]# python3 signal_ignore.py 
    我的PID: 15042
    ^C^C^C^C^C^C^C

    #终端2
    #方法1、杀死不了进程
    [root@ mnt]# kill -INT 15042 

    #方法2、可以杀死进程
    [root@ mnt]# kill -USR1 15042

6、开启两个线程相互接收信号

#!/usr/bin/env python
    # -*- coding: utf-8 -*-

    import signal
    import threading
    import os
    import time

    def signal_handler(num, stack):
        print('接收信号 SIG值{} 线程名字{}'.format(num, threading.currentThread().name))

    # 给SIGUSR1注册处理事件
    signal.signal(signal.SIGUSR1, signal_handler)

    #等待接收信号
    def wait_for_signal():
        print('等待信号进来', threading.currentThread().name)
        signal.pause()
        print('完成等持')


    # 启动不会接收信号的线程
    receiver = threading.Thread(
        target=wait_for_signal,
        name='receiver',
    )
    receiver.start()
    time.sleep(0.1)

    #给主进程发送SIGUSR1信号
    def send_signal():
        print('发送SIGUSR1信号', threading.currentThread().name)
        os.kill(os.getpid(), signal.SIGUSR1)

    sender = threading.Thread(target=send_signal, name='sender')
    sender.start()
    sender.join()

    # 等待线程看到信号
    print('Waiting for', receiver.name)
    signal.alarm(2) #2秒后,发出告警信号,终止程序,如果没有加入此代码,会导致无限阻塞
    receiver.join()

signal_threads.py

运行效果

[root@ mnt]# python3 signal_threads.py      
    等待信号进来 receiver
    发送SIGUSR1信号 sender
    接收信号 SIG值10 线程名字MainThread
    Waiting for receiver
    Alarm clock

7、多进程与告警信号配合使用

#!/usr/bin/env python
    # -*- coding: utf-8 -*-

    import signal
    import time
    import threading

    def signal_handler(num, stack):
        print(time.ctime(), '处理告警的线程名字', threading.currentThread().name)


    # 注册SIGALRM信号的事件
    signal.signal(signal.SIGALRM, signal_handler)


    def use_alarm():
        t_name = threading.currentThread().name
        print(time.ctime(), '设置1秒后触发告警', t_name)
        signal.alarm(1)
        print(time.ctime(), '睡眠3秒', t_name)
        time.sleep(3)
        print(time.ctime(), '完成睡眠', 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(), '等待执行完成', alarm_thread.name)
    alarm_thread.join()

    print(time.ctime(), '正常退出')

signal_threads_alarm.py

运行效果

[root@ mnt]# python3 signal_threads_alarm.py 
    Thu Dec  5 16:37:05 2019 设置1秒后触发告警 alarm_thread
    Thu Dec  5 16:37:05 2019 睡眠3 alarm_thread
    Thu Dec  5 16:37:05 2019 等待执行完成 alarm_thread
    Thu Dec  5 16:37:06 2019 处理告警的线程名字 MainThread
    Thu Dec  5 16:37:08 2019 完成睡眠 alarm_thread
    Thu Dec  5 16:37:08 2019 正常退出


原文链接:https://www.cnblogs.com/ygbh/p/11989483.html