• signal 信号


    基于python学习笔记——多进程间通信——Linux信号基础的学习基础,进一步学习Python标准库中的signal模块。

    尽管signal是python中的模块,但是主要针对UNIX平台(比如Linux,MAC OS),而Windows内核中由于对信号机制的支持不充分,所以在Windows上的Python不能发挥信号系统的功能。

    signal模块负责python程序内部的信号处理;典型的操作包括信号处理函数、暂停并等待信号,以及定时发出SIGALRM等;

    1 signal基本信号名

    import signal
    
    signal.SIGHUP   # 连接挂断;
    signal.SIGILL   # 非法指令;
    signal.SIGINT   # 终止进程(ctrl+c);
    signal.SIGTSTP  # 暂停进程(ctrl+z);
    signal.SIGKILL  # 杀死进程(此信号不能被捕获或忽略);
    signal.SIGQUIT  # 终端退出;
    signal.SIGTERM  # 终止信号,软件终止信号;
    signal.SIGALRM  # 闹钟信号,由signal.alarm()发起;
    signal.SIGCONT  # 继续执行暂停进程;

    2、 常用信号处理函数

    2.1 设置发送SIGALRM信号的定时器

    import signal
    import time
    
    signal.alarm(4)#4s后终止程序
    
    while True:
        time.sleep(1)
        print("学习python中...")
    学习python中...
    学习python中...
    学习python中...
    闹钟

    注意:在一个进程中,只能设置一个定时闹钟。如果设置第二个则会覆盖第一个的时间,返回地一个的剩余时间,第一个闹钟返回0。

    使用signal.pasue阻塞函数:

    signal.pause() Wait until a signal arrives。让进程进程暂停,以等待信号(什么信号均可);也即阻塞进程进行,但不阻塞其他信号,接收到信号后使进程停止

    import signal
    import time
    
    print(signal.alarm(3)) # 0
    time.sleep(1)
    print(signal.alarm(4)) # 3
    
    #阻塞等待信号的发生,如论什么信号都可以
    signal.pause()
    
    while True:
        time.sleep(1)
        print("学习python中...")
    0
    2
    闹钟

    2.2 设置信号处理函数

     signal.signal(sig, handler) 

    功能:按照handler制定的信号处理方案处理函数

    参数

    sig:拟需处理的信号,处理信号只针对这一种信号起作用sig

    hander:信号处理方案

        在信号基础里提到,进程可以无视信号、可采取默认操作、还可自定义操作;当handler为下列函数时,将有如下操作:

        SIG_IGN:信号被无视(ignore)或忽略

        SIG_DFL:进程采用默认(default)行为处理

       function:handler为一个函数名时,进程采用自定义函数处理

       不能处理,只能采用 也就是说hander的值有效值只有上面三种:否则报错 TypeError: signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object

    示例代码一、

    import signal
    
    #6s后终止程序
    signal.alarm(6)
    
    #遇到SIGINT ctrl+c时,忽略SIG_IGN
    signal.signal(signal.SIGINT,signal.SIG_IGN)
    
    signal.pause()
    运行后6s 打印出: Alarm clock 
    
    如果在运行中在键盘中输入CTRL+C也无济于事,此时输出结果 ^C^C^C^C^C^C^C^C Alarm clock
    
    
    原因分析
    
    (1)signal.signal(signal.SIGINT, signal.SIG_IGN) 表示遇到信号SIGINT  CTRL + C,时,忽略SIG_IGN该信号。
    
    所以在程序运行中从键盘输入ctrl+c(在终端上显示 ^C )时无效。
    
    (2)当signal.alarm(6)计时6秒后,直接在终端上输出 “闹钟” 后退出。
    
    (3)signal.pause()是为了阻塞进程,等待信号。如果没有这句话,可以在程序中更变为
    
    while True:
        pass
    效果一样,如果没有这段代码,则没有直接运行结束,终端上没有任何输出显示。注意:这里的signal.alarm()是在程序运行中,6秒后停止进程。

    示例代码二:

    #进程中默认信号方式处理
    import signal
    #6s后终止程序
    signal.alarm(6)
    signal.signal(signal.SIGALRM,signal.SIG_DFL) #遇到闹钟信号按默认方式处理
    signal.pause()#等信号。

    示例代码三:捕获信号交给函数处理

    有些原操作系统规定了的进程收到信号后的默认行为,使用signal.signal()可以通过绑定信号处理函数来修改进程收到信号后的行为,实现个性化处理。

    也即改变原默认行为。

    from signal import *
    import time
    
    def handler(signum,frame):
        if signum == SIGALRM:
            print('时间到了')
        elif signum == SIGINT:
            print("CTRL + C 无效")
    
    alarm(5)
    signal(SIGINT,handler)
    signal(SIGALRM,handler)
    
    
    while True:
        print('Waiting....')
        time.sleep(2)

    这个代码运行导致ctrl +c 无法中断运行

    Waiting....
    Waiting....
    Waiting....
    时间到了
    Waiting....
    ^CCTRL + C 无效
    Waiting....
    ^CCTRL + C 无效
    Waiting....

    说明:

    (1)signal.signal() 通过绑定函数更变了信号的处理方式

    (2)如果没有改变alarm()信号的处理方式,signal.alarm()在运行5s后会将终止程序并输出“闹钟”字样

    (3)从设备终端键盘输入ctrl+c无效后,此时可以输入ctrl+退出程序

    (4)def handler(signum,frame)中frame,第一个参数是用来识别信号(signum),第二个信号是用来获得信号发生时,进程栈的状况(stack frame对象),这两个参数都是由signal.signal()函数传递的。 参考 Frame objects

    示例四:

    CTRL+ Z信号

    import signal
    
    # Define signal handler function
    def myHandler(signum, frame):
        print('I received: ', signum)
    
    # register signal.SIGTSTP's handler
    signal.signal(signal.SIGTSTP, myHandler)
    signal.pause()
    print('End of Signal Demo')
    ^ZI received:  20
    I frame:  <frame at 0x7f0e1a1b29f8, file 'test6.py', line 10, code <module>>
    End of Signal Demo
    (base) [root@vm192-168-3-2 signal_study]# 

    说明:

    (1)signal.signal()函数来预设信号处理函数;

    (2)当程序执行signal.pause()来让进程暂停(被阻塞)以等待信号,此时,按下ctrl + z 向该进程发送SIGTSTP信号,当信号signal.SIGTSTP信号传递给该进程后,进程从被阻塞中恢复,并根据预设,执行SIGTSTP的信号处理函数myHandler()。

    (3)myHandler()的两个参数一个用来识别信号(signum),另一个用来获得信号发生时,进程栈的状况(stack frame);这两个参数都是有signal.signal()函数传递的。

    (4)进程并不一定要使用signal.pause()暂停以等待信号,它也可以在进行工作中接受信号,比如将上面的signal.pause()改为一个需要长时间工作的循环或死循环。

    3 常用信号处理函数总结

     signal.signal(signalnum, handler)  设置信号处理的函数

     signal.alarm(time) 设置发送SIGALRM信号的定时器

     os.kill 这个不属于signal模块,但其可以使用给某一进程发送信号

    可以捕获的

    signal.SIGHUP   # 连接挂断;
    signal.SIGILL   # 非法指令;
    signal.SIGINT   # 终止进程(ctrl+c);
    signal.SIGTSTP  # 暂停进程(ctrl+z);
    signal.SIGQUIT  # 终端退出;
    signal.SIGTERM  # 终止信号,软件终止信号;
    signal.SIGALRM  # 闹钟信号,由signal.alarm()发起;
    signal.SIGCONT  # 继续执行暂停进程;

    不可以被捕获的:
    signal.SIGKILL # 杀死进程(此信号不能被捕获或忽略);
    信号如何处理:只能 忽略/默认 或者自定义函数处理 signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object
  • 相关阅读:
    Mina、Netty、Twisted一起学(七):公布/订阅(Publish/Subscribe)
    MySQL高可用之——keepalived+互为主从
    JS之BOM
    Mac下利用(xcode)安装git
    计算矩阵边缘元素之和
    什么是猴子补丁(monkey patch)
    协议支撑
    BZOJ 3727 PA2014 Final Zadanie 树形DP
    Linux cat命令
    iOS8新特性
  • 原文地址:https://www.cnblogs.com/zhangmingda/p/11722737.html
Copyright © 2020-2023  润新知