「信号机制」Python信号处理—sig

发布时间:2019-09-25 08:28:32编辑:auto阅读(3093)

    转载请注明出处:https://blog.csdn.net/jinixin/article/details/80383177

     

    本文是信号机制三篇记录中的第二篇,介绍Python语言中负责信号处理的signal模块,并会给出一些小demo;第一篇简单介绍了Linux信号机制,第三篇则给出关于信号的一个应用。三篇组成一个系列,想起抛砖引玉的作用,希望对大家能有所帮助。

     

     

    signal模块

     

    该模块提供Python中信号处理的机制,下面是几个常用的方法

    1. signal.signal(signalnum, handler)

    注册signalnum信号量的处理函数为handler

    其中signalnum为待注册的信号量,handler为该信号量的处理器,其是一个可调用对象,该对象必须接受两个参数,分别是信号量signum,当前程序运行堆栈frame,这两个参数Python解释器会自动传入,因此我们不必显示传入。关于如何打印堆栈frame的值,可以参考这篇博客

     

    这时你也许有疑问,上篇博客中不是说程序可以忽略信号吗?

    那是不是说忽略就是直接在handler的函数体中写个pass就行呢?其实这么想没有错,因为处理完信号后,程序会回到接收到信号的地方继续运行,但这样写就不简洁了。其实handler除了是可调用对象外,还可以是以下两个常量:

    1)当handler为signal.SIG_DFL时,表示接收信号后,程序按系统默认行为执行;

    2)当handler为signal.SIG_IGN时,则表示接收信号后,程序忽略该信号,继续自身运行。

     

    关于该方法有两个注意点:

    1)该方法是有返回值的,其将返回之前原有的信号处理函数;

    2)该方法仅能在主线程中注册信号处理器,若在子线程中注册,将引发ValueError异常。

     

    2. signal.getsignal(signalnum)

    返回目前程序注册signalnum信号量的处理函数

    返回值可能是Python可调用对象,signal.SIG_DFL,signal.SIG_IGN或None。

     

    3. signal.pause()

    使程序进入睡眠,直到程序接收到某个信号量

     

    4. signal.alarm(time)

    每隔time秒发出一个ALRM信号

    若注册了ALRM信号的处理函数,则相关处理器会被调用。当time为0时,取消注册ALRM信号处理函数。

     

     

    如何发送信号

     

     

    1)如果在命令行中,可以用kill命令向对应进程发送信号,或者使用快捷键(如「CTRL-C」,Python程序会收到SIGINT信号),具体可参考上篇博客

    2)如果在Python程序中,则可借助Python的os模块:

    os.kill(pid, signal):向进程号pid对应进程发送signal信号量

    而进程号的获取,则可以借助下面两个方法:

    os.getpid():获取程序的进程ID

    os.getppid():获取程序的父进程ID

     

     

     

    案例

     

    案例一:注册SIGUSR1信号处理器,并在执行过程向程序发送SIGUSR1信号,调起对应处理器

    #!/usr/bin/env python3
    # coding=utf-8
    
    import os
    import time
    import signal
    import traceback
    
    
    def handle_SIGUSR1(signum, frame):
        print('handle sighup!{0}{1}'.format(os.linesep, '*' * 100))
        print(os.linesep.join(traceback.format_stack(frame)))  # 打印详细运行信息
    
    
    def main():
        signal.signal(signal.SIGUSR1, handle_SIGUSR1)  # 注册SIGUSR1信号的处理器为handle_SIGUSR1函数
        print(signal.getsignal(signal.SIGUSR1))        # 获取SIGUSR1信号目前的处理器
    
        time.sleep(3)  # 或者使用signal.pause()
        os.kill(os.getpid(), signal.SIGUSR1)  # 向当前进程发送SIGUSR1信号
        time.sleep(3)
    
        print('done')
    
    
    if __name__ == '__main__':
        main()
    

    运行结果:

     

    案例二:在子线程中注册某信号量的处理器,报错

    #!/usr/bin/env python3
    # coding=utf-8
    
    
    from threading import Thread
    import signal
    
    
    def child():
        signal.signal(signal.SIGUSR1, signal.SIG_IGN)  # 注册SIGUSR1信号的处理器为signal.SIG_IGN,即忽略
        print('child thread')
    
    
    def main():
        thread = Thread(target=child)
        thread.start()  # 开启子线程
        thread.join()
        print('done')
    
    
    if __name__ == '__main__':
        main()
    

    运行结果:

     

    案例三:注册SIGCHLD信号处理器,子进程结束执行后触发SIGCHLD信号,父进程接收

    #!/usr/bin/env python3
    # coding=utf-8
    
    import os
    import signal
    
    
    def handle_SIGCHLD(signum, frame):
        print('handle child process')
    
    
    def main():
        signal.signal(signal.SIGCHLD, handle_SIGCHLD)  # 注册SIGCHLD信号的处理器为handle_SIGCHLD函数
        pid = os.fork()
        if pid == 0:
            print('child process')  # 子进程结束执行后,会向父进程发送SIGCHLD信号
        else:
            print('main process')
            os.wait()
    
        print('done')
    
    
    if __name__ == '__main__':
        main()
    

    运行结果:

     

    案例四:注册SIGALRM信号处理器,定时发送SIGALRM信号

    #!/usr/bin/env python3
    # coding=utf-8
    
    import time
    import signal
    
    
    def handle_SIGALRM(signum, frame):
        print('alarm {0}!'.format(int(time.time())))
    
    
    def main():
        signal.signal(signal.SIGALRM, handle_SIGALRM)  # 注册SIGALRM信号的处理器为handle_SIGALRM函数
    
        signal.alarm(3)  # 设置每3秒发送一次SIGALRM信号
        time.sleep(10)   # 某些耗时的操作
        signal.alarm(0)  # 取消定时发送SIGALRM信号
    
        print('done')
    
    
    if __name__ == '__main__':
        main()

    运行结果:

     

    对于信号量的用途,大家有兴趣可以看这篇博客

     

     

    文中如有不当之处,还望大家包容和指出,感谢~

     

    参考链接:
    https://docs.python.org/3/library/signal.html

     

关键字