信号Signal

信号Signal的全称为软中断信号,是用来通知进程发生了异步事件,是在软件层次上对中断机制的一种模拟。原理上一个进程收到一个信号与CPU收到一个中断请求可以说是类似的。

信号是进程间通信机制中唯一的异步通信机制,一个进程不必通过任何操作来等待信号的到达。事实上进程也不知道信号到底什么时候到达,进程之间可以相互通过系统调用kill发送软中断信号。内核也可以因为内部事件而给进程发送信号,通知进程发生了某个事件。信号机制除了基本通知功能外,还可以传递附加信息。

信号是Linux系统编程中非常重要的概念,信号机制是进程间传递消息的一种机制,是异步进程中通信的一种方式。比如终端用户输出Ctrl+c来终端程序时会通过信号机制停止程序的执行。

信号的作用是通知进程发生了异步事件,进程之间可以调用系统传递信号,内核本身也可以发送信号给进程,告知该进程发生了某个事件。在应用层可以将消息传递给内核监控,当消息处理完毕后,内核将消息反馈给应用层,这样操作不会出现阻塞等待,保持信号处理的持续性。

相对于共享内存,信号更加偏向于系统层面,Linux系统也是通过信号管理进程的,而且系统规定了某些进程接收到某些信号后的行为 。

一个进程一旦接收到信号就会打断原来的程序执行流程来处理信号。不过需要注意要的是,信号只是用来通知某进程发生了什么事件,并不会给该进程传递任何数据。

信号生命周期

对于一个完整的信号生命周期,从信号发送到相应的处理函数执行完毕来说,,可以以分为三个阶段:信号诞生、信号在进程中注册、信号的执行和注销。

  • 信号诞生

信号事件的发生有两个来源分别是硬件来源和软件来源,最常用发送信号的系统函数是killraisealarmsettimersigqueue,软件来源还包含一些非法运算等操作。

  • 信号在目标进程中注册

在进程表的表项中有一个软中断信号域,该域中每一位对应一个信号。内核给一个进程发送软中断信号的方法,是在进程所在的进程表项的信号域中设置对应于该信号的位。如果信号发送给一个正在休眠的进程,此时如果进程睡眠在可被中断的优先级上则会唤醒进程,否则仅设置进程表中信号域相应的位而不唤醒进程。如果发送给一个处于正在运行状态的进程则只置相应的域即可。

  • 信号的执行和注销

内核处理一个进程收到的软中断信号是在该进程的上下问,因此进程必须处于运行状态。当其被信号唤醒或正常调度重新获得CPU时,再从内核空间返回到用过户空间时会检测是否有信号等待处理。如果存在未决信号等待处理且该信号没有被进程阻塞,则在运行相应的信号处理函数前,进程会将信号在未决信号链中占有的结构卸掉。

信号处理

接收信号的进程对不同的信号有三种处理方式:指定处理函数、忽略、根据系统默认值处理(大部分信号的默认处理时终止进程)。

  • 忽略信号

大多数信号可以使用忽略信号这种方式来处理,但有两种信号不能被忽略,分别是SIGKILLSIGSTOP。因为它们向内核和超级 与用户提供了进程终止和停止的可靠方法。如果忽略了,那么进程就 会变的没人能够管理,显然这是内核设计者不希望看到的场景。

  • 捕捉(指定处理函数)

需要告知内核用户希望如何处理某一种信号,简单来说就是写一个信号处理函数,然后将这个函数告诉内核。当该信号产生时,由内核来调度用户自定义的函数,以此实现某种信号的处理。

  • 系统默认动作

对于每个信号来说,系统都对应有默认的处理动作,当发生了该信号系统会自动执行。不过对系统来说,大部分的处理方式都比较粗暴,也就是直接杀死该进程。

信号表示

每个信号都有一个名字和编号,这些名字都是以SIG开头,信号定义在signal.h头文件中,其中信号名都定义为正整数,具体的信号名称可以通过kill -l来查看。信号是从1开始编号,不存在0号信号,因为kill对信号0有特殊的应用。

对于常用的kill命令其实是一个发送信号的工具,比如使用kill -9 PID来杀死指定PID的进程,其中-9表示信号列表中9号即SIGKILL信号,表示杀死该进程的信号。

$ kill -l1) SIGHUP   2) SIGINT   3) SIGQUIT  4) SIGILL   5) SIGTRAP6) SIGABRT  7) SIGBUS   8) SIGFPE   9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG  24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF 28) SIGWINCH    29) SIGIO   30) SIGPWR
31) SIGSYS  34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

信号分类

  • POSIX标准规则信号regular signal 1-31
  • 实时信号real-time signal 32-63

由于不同系统中同一个数值对应的信号类型不同,所以最好使用信号名称。另外,信号的数值越小,优先级越高。

信号通信

  • 被动式
    内核检测到一个系统事件,比如子进程退出时会向父进程发送SIGCHLD信号,当键盘按下Ctrl+C时会发送SIGINT信号等。
  • 主动式
    比如通过系统调用kill向指定进程发送信号

常见信号

  • SIGINT 表示键盘按下Ctrl+c键时会发送给前台的每一个进程。
  • SIGQUIT 表示键盘按下Ctrl+\
  • SIGSTP 表示键盘按下Ctrl+z
  • SIGKILL 表示结束某个进程,不能被忽略处理。
  • SIGALRM 表示时钟信号,常用作定时器。
  • SIGSTOP表示暂停某个进程,且不能被忽略处理。
  • SIGCHLD表示子进程发送给父进程信号

可以在中断输入kill -l命令查看系统支持的所有信号列表

kill -l [信号声明]
kill [-s 信号声明 | -n 信号编号 | -信号声明] 进程号 | 任务声明...
  • 在信号列表中,34号之后的信号尚未定义。
  • 进程结束信号可使用SIGKILLSIGTERM
    • 对于SIGKILL结束信号时,进程是不能忽略的,该信号意味着不管进程正在做什么都必须立即停止。
    • 对于SIGTERM结束信号是比较友好的,进程能捕捉到这个信号,会根据用户的需要来关闭程序。在关闭程序之前,可以结束打开的记录文件和完成正在做的任务。在某些情况下,假如进程正在进行作业而且不能中断,那么进程可以忽略这个SIGTERM信号。

Python信号模块signal

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

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

加载模块

import signal

信号名称

# 连接挂断
signal.SIGUP
# 非法指令
signal.SIGILL
# 终止进程
signal.SIGINT

SIGINT信号编号为2,当按下键盘CTRL+c组合键时进程会收到此信号,用于终止进程。

# 暂停进程CTRL+z
signal.SIGSTP
# 杀死进程,此信号不能被捕获或忽略。
signal.SIGKILL

SIGKILL信号用于强制杀死进程,此信号进程无法忽视,直接在系统层面将进程杀死,所以在Python中它是不能监听的。

# 终端退出
signal.SIGQUIT
# 终止信号,软件终止信号。
signal.SIGTERM

当终端用户输入kill sigerm pid时对应PID的进程会接收到此信号,此信号进程是可以捕获并指定函数处理。比如做一下程序清理等工作,当然也是可以忽视此信号的。

# 闹钟信号,由signal.alarm()发起。
signal.SIGALRM
# 继续执行暂停进程
signal.SIGCONT

信号处理函数

设置发送SIGALRM信号的定时器

signal.alarm(time)
  • 功能:在time秒后向进程自身发送SIGALRM信号
  • 参数:time为时间参数,单位为秒。

例如:设置时钟

$ vim sigalrm.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-import signal, time# 3秒后终止程序
signal.alarm(3)while True:time.sleep(1)print("working")
$ python sigalrm.py
working
working
闹钟

一个进程中只能设置一个时钟,如果设置第二个则会覆盖第一个的时间,并返回第一个的剩余时间,同时第一个闹钟返回为0。

例如:当在一个程序中出现两个signal.alarm()函数时

$ vim sigalrm.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-import signal, time# 3秒后终止程序
print(signal.alarm(3)) # output:0
time.sleep(1)
print(signal.alarm(3)) # output:2while True:time.sleep(1)print("working")
$ python sigalrm.py
0
2
working
working
闹钟

使用signal.pause阻塞函数,让进程暂停以等待信号,也就时阻塞进程执行,简单来说当接收到信号后使进程停止。

例如:

$ vim sigalrm.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-import signal, time# 3秒后终止程序
print(signal.alarm(3)) # output:0
time.sleep(1)
print(signal.alarm(3)) # output:2# 阻塞等待信号的发生,无论什么信号都可以。
signal.pause()while True:time.sleep(1)print("working")
$ python sigalrm.py
0
2
闹钟

使程序进入休眠

signal.pause()
  • 作用:使程序进入休眠直到程序接收到某个信号量

获取当前程序注册signalnum信号量的处理函数

signal.getsignal(signalnum)
  • 作用:获取当前程序注册signalnum信号量的处理函数
  • 返回值:可能使Python可调用对象如signal.SIG_DFLsignal.SIG_IGNNone

设置信号处理函数

signal.signal(sig, handler)
  • 功能:按照handler处理器制定的信号处理方案处理函数
  • 参数:
    • sig拟需处理的信号 ,处理函数只针对这一种信号其作用。
    • handler信号处理函数,进程可以无视信号采取默认操作也可自定义操作。

handler为下列函数时将有如下操作

  • SIG_IGN信号被无视ignore或忽略
  • SIG_DFL进程采用默认default行为处理
  • function处理器handler作为函数名称时,进程采用自定义函数处理。
  • SIGSTOP SIGKILL不能处理只能采用

例如:

$ vim signal.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-import signal, time# 3秒后终止程序
signal.alarm(3)
# 当遇到SIGINT即CTRL+C时忽略SIG_IGN
signal.signal(signal.SIGINT, signal.SIG_IGN)
# 阻塞等待信号的发生,无论什么信号都可以。
signal.pause()
$ python signal.py
闹钟

信号拦截

为什么需要设置信号拦截呢?如果使用多线程或多协程,为了防止主线程结束而子线程和子协程还在运行,此时就需要使用signal模块,使用signal模块可以绑定一个处理函数,当接收步到信号的时候不会立即结束程序。

在Python中拦截信号通常有两种方式

  • 第一种是发出kill信号
# SIGTERM 表示关闭程序信号
signal.signal(signal.SIGTERM, self._term_handler)
  • 第二种是发出CTRL+C信号
# SIGINT表示CTRL+C信号
signal.signal(signal.SIGINT, self._term_handler)

在多线程多协程的程序设计时,一般多线程或的多协程程序在设计时应该设计一个程序终止标记,当收到终止信号的时候,让终止标记状态由False修改为True,此时运行的程序只有终止标记在False状态下时才能够以运行。

如果由需要休眠的协程,还应给协程增加一个休眠标记,当程序休眠的时候休眠标记设置为True,当收到终止信号的时候,不仅仅要把终止标记设置为True,还要将休眠中的协程结束掉。

python(10): Signal相关推荐

  1. 浅析Python中signal包的使用

    原文链接:https://www.jb51.net/article/74844.htm 这篇文章主要介绍了Python中signal包的使用,主要在Linux系统下对进程信号进行相关操作,需要的朋友可 ...

  2. 设计模式 with Python 10:状态模式

    设计模式 with Python 10:状态模式 如果你接触过UML的状态图,应该会对状态图或者状态机有所了解,我们今天讨论的状态模式就是这种设计的落地方案. 和之前的讲解一样,我们从一个具体案例&q ...

  3. (收藏)Python 10个正则表达式写法

    关于Python 10个正则表达式写法 主要是用到了 re这个库 (1).其中re.compile用于编译正则表达式,生成一个正则表达式( Pattern )对象 (2). .findall用于在字符 ...

  4. python模块—signal

    文章目录 信号 介绍 生命周期 信号处理 信号表示 信号分类 信号通信 常用信号 python signal 信号 介绍 信号signal的全称是软中断信号,是用来通知进程发生的异步事件,是在软件层次 ...

  5. python nextpow2_Python signal.hann方法代码示例

    本文整理汇总了Python中scipy.signal.hann方法的典型用法代码示例.如果您正苦于以下问题:Python signal.hann方法的具体用法?Python signal.hann怎么 ...

  6. python之signal操作

    1 信号的意义 在linux系统中信号是与进程通信的一种手段.假设没有信号,linux中的进程一旦运行起来将不再受控,这种局面对于进程的管理来说是一种灾难.kill.ctrl+c等操作本质上就是我们向 ...

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

    转载请注明出处:https://blog.csdn.net/jinixin/article/details/80383177 本文是信号机制三篇记录中的第二篇,介绍Python语言中负责信号处理的si ...

  8. python 信号模块 signal

    在了解了Linux的信号基础之 后,Python标准库中的signal包就很容易学习和理解.signal包负责在Python程序内部处理信号,典型的操作包括预设信号处理函数,暂 停并等待信号,以及定时 ...

  9. python生成词云很慢吗_词云制作没那么难,Python 10 行代码就实现了!

    写在前面 想必大家有一个问题.什么是词云呢? 词云又叫名字云,是对文本数据中出现频率较高的"关键词"在视觉上的突出呈现,形成关键词的渲染形成类似云一样的彩色图片,从而一眼就可以领略 ...

最新文章

  1. C++二维数组new小结(zz)
  2. ansys结构分析单元与应用_结构动力学中的时域分析(3) —— 基于ANSYS的实现
  3. 史上最完整的文件和目录操作类
  4. CSS五种水平居中:text-align margin incline-block flex relative
  5. python图像卷积_图像处理——卷积原理、二维卷积python实现
  6. java ipmitool_ipmitool使用手册
  7. jq追加元素最前面_DNF:哈林史诗百鬼夜行最理想的首饰搭配,海博伦应选贤者之欲...
  8. VMware Sphere 虚拟磁盘创建选项
  9. 详解:什么是VXLAN?
  10. 怎么白嫖一部好手机?我来告诉你
  11. C/C++编程:仿函数
  12. 忆我的大学老师----(一)
  13. 程序员的自我修养 - 读书笔记文字版
  14. 干货 | PID算法在广告成本控制领域的应用
  15. 设计模式之访问者模式(C++)
  16. WRFDA教程:3DVar同化卫星辐射率资料
  17. 降碳为先 成本为王!绿色数据中心的能源“新”解法
  18. 2021前端react面试题汇总
  19. fortran:计算第二类椭圆积分
  20. 爱丁堡大学计算机专业本科要求,爱丁堡大学计算机专业简单介绍及入学条件

热门文章

  1. mysql数据库recover_xxx数据库恢复 mariadb数据库误删除恢复 mysql数据库被黑删库恢复
  2. Java-- Maps
  3. Java 小例子:分解质因数
  4. boost:lexical_cast
  5. mysql cast 和 pgsql cast
  6. 人脸识别SVM算法实现--参考麦子学院彭亮机器学习基础5.2
  7. 06年计算机竞赛,2006年数学建模校内竞赛结果
  8. JS实现右键拖动元素
  9. 史上最全 | 基于深度学习的3D分割综述(RGB-D/点云/体素/多目)
  10. 新概念三英语学习Unit2