「信号机制」Python信号处理—signal模块

转载请注明出处: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

 

  • 8
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: signal模块提供了一种将信号发送到Python程序中的方法,它可以在外部事件发生时调用特定的函数。signal.signal函数接受两个参数:信号的数字标识符和要调用的函数。例如,要设置SIGINT(中断进程)信号,可以使用以下代码:signal.signal(signal.SIGINT, my_handler)。 ### 回答2: 在Python中,signal.signal()函数用于设置信号处理函数,即在程序中捕捉到特定信号时执行指定操作。这个函数的基本用法如下: 首先,需要导入signal模块: ```python import signal ``` 然后,我们可以定义一个函数来处理信号,这个函数通常需要带有两个参数(一个是信号编号,一个是当前调用的栈帧): ```python def signal_handler(signal, frame): # 执行特定操作 print('接收到信号') ``` 接下来,使用signal.signal()函数来设置信号处理函数: ```python signal.signal(signal.SIGUSR1, signal_handler) ``` 其中,signal.SIGUSR1是定义的一个信号常量,代表用户自定义的信号1,可以根据需要替换为其他信号常量。signal_handler是我们自定义的信号处理函数。 最后,可以通过发送信号来触发信号处理函数的执行: ```python import os os.kill(os.getpid(), signal.SIGUSR1) ``` 上述代码会向当前进程发送一个SIGUSR1信号,从而触发相应的信号处理函数的执行。在这个例子中,会打印出"接收到信号"的消息。 需要注意的是,Python信号处理函数默认情况下只在主线程中执行。如果需要在子线程中处理信号,需设置线程信号函数的特殊标志: ```python signal.signal(signal.SIGUSR1, signal.SIG_IGN) # 忽略信号 signal.signal(signal.SIGUSR1, signal.SIG_DFL) # 使用默认处理函数 ``` 总之,signal.signal()函数能够让我们在Python中捕捉和处理各种信号,使得程序的执行更加灵活和可控。 ### 回答3: 在Python中,signal模块提供了signal.signal函数,用于设置信号处理程序。其用法如下: 首先,需要导入signal模块: import signal 然后,定义一个信号处理函数,该函数用于处理接收到的信号。函数的参数是信号编号以及当前堆栈的帧对象: def signal_handler(signal, frame): print('接收到信号') 接下来,使用signal.signal函数来设置信号处理程序。该函数有两个参数,第一个参数是要处理的信号编号,而第二个参数是信号处理函数: signal.signal(signal.SIGINT, signal_handler) 在这个例子中,我们将SIGINT信号(也就是Ctrl+C组合键)与signal_handler函数关联起来。当接收到SIGINT信号时,程序将调用signal_handler函数。 最后,我们可以通过调用signal.pause函数来使程序进入等待状态,等待信号的到来: signal.pause() 总结起来,使用signal.signal函数需要三个步骤:导入signal模块、定义信号处理函数、以及使用signal.signal函数设置信号处理程序。这样,程序就可以在接收到指定信号时调用特定的处理函数来进行相应的操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值