Python和Signal
先简单说一下Signal是啥.(如果想直接使用可以不看)
Signal翻译过来中文就是信号- -
当然, 本身他就是Linux系统编程中非常重要的概念, 信号机制是进程之间传递消息的一种机制,
其全称为软中断信号
作用是通知进程发生了异步事件。进程之间可以调用系统来传递信号, 本身内核也可以发送信号给进程, 告诉该进程发生了某个事件.
注意,信号只是用来通知某进程发生了什么事件,并不给该进程传递任何数据。
接收信号的进程对不同的信号有三种处理方法
- 指定处理函数
 - 忽略
 - 根据系统默认值处理, 大部分信号的默认处理是终止进程
 
然后就是一大段类型了..
Linux系统有两大类信号
- POSIX标准的规则信号(regular signal 1-31编号)
 - 实时信号(real-time signal 32-63)
 
规则信号
| 信号编号 | 名称 | 默认动作 | 说明 | 
|---|---|---|---|
| 1 | SIGHUP | 终止 | 终止控制终端或进程 | 
| 2 | SIGINT | 终止 | 由键盘引起的终端(Ctrl-c) | 
| 3 | SIGQUIT | dump | 控制终端发送给进程的信号, 键盘产生的退出(Ctrl-\), | 
| 4 | GIGILL | dusmp | 非法指令引起 | 
| 5 | SIGTRAP | dump | debug中断 | 
| 6 | SIGABRT/SIGIOT | dump | 异常中止 | 
| 7 | SIGBUS/SIGEMT | dump | 总线异常/EMT指令 | 
| 8 | SIGFPE | dump | 浮点运算溢出 | 
| 9 | SIGKILL | 终止 | 强制杀死进程(大招, 进程不可捕获) | 
| 10 | SIGUSR1 | 终止 | 用户信号, 进程可自定义用途 | 
| 11 | SIGSEGV | dump | 非法内存地址引起 | 
| 12 | SIGUSR2 | 终止 | 用户信号, 进程可自定义用途 | 
| 13 | SIGPIPE | 终止 | 向某个没有读取的管道中写入数据 | 
| 14 | SIGALRM | 终止 | 时钟中断(闹钟) | 
| 15 | SIGTERM | 终止 | 进程终止(进程可捕获) | 
| 16 | SIGSTKFLT | 终止 | 协处理器栈错误 | 
| 17 | SIGCHLD | 忽略 | 子进程退出或中断 | 
| 18 | SIGCONT | 继续 | 如进程停止状态则开始运行 | 
| 19 | SIGSTOP | 停止 | 停止进程运行 | 
| 20 | SIGSTP | 停止 | 键盘产生的停止 | 
| 21 | SIGTTIN | 停止 | 后台进程请求输入 | 
| 22 | SIGTTOU | 停止 | 后台进程请求输出 | 
| 23 | SIGURG | 忽略 | socket发送紧急情况 | 
| 24 | SIGXCPU | dump | CPU时间限制被打破 | 
| 25 | SIGXFSZ | dump | 文件大小限制被打破 | 
| 26 | SIGVTALRM | 终止 | 虚拟定时时钟 | 
| 27 | SIGPROF | 终止 | profile timer clock | 
| 28 | SIGWINCH | 忽略 | 窗口尺寸调整 | 
| 29 | SIGIO/SIGPOLL | 终止 | I/O可用 | 
| 30 | SIGPWR | 终止 | 电源异常 | 
| 31 | SIGSYS/SYSUNUSED | dump | 系统调用异常 | 
注意: 由于不同系统中同一个数值对应的信号类型不一样, 所以最好使用信号名称.
信号的数值越小, 优先级越高.
OK, 现在来说说Python中的处理
先列几个常用的信号:
| 编号 | 信号名称 | 说明 | 
|---|---|---|
| 2 | SIGINT | 当按下键盘(Ctrl-c)组合键时进程就会收到这个信号 | 
| 15 | SIGTERM | 当用户输入 kill sigterm pid. 对应的进程就会收到这个信号. 这个信号进程是可以捕获并指定函数处理, 例如做一下程序清理等工作. 甚至忽视这个信号 | 
| 9 | SIGKILL | 强制杀死进程, 这个信号进程无法忽视, 直接在系统层面把进程杀掉. 所以在Python中他的不能监听的 | 
| 14 | SIGALRM | 闹钟信号 | 
去码
先来一个例子
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
    监听了SIGINT信号, 当程序在运行的时候同时按下键盘 Ctrl+c 就会输出
    收到信号 2 <frame object at 0x00000000021DD048>
    handler方法的两个参数分别是 信号编号, 程序帧
"""
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
import time
import os
import signal
receive_times = 0
def handler(signalnum, handler):
    global receive_times
    print u"收到信号", signalnum, frame, receive_times
    receive_times += 1
    if receive_times > 3:
        exit(0) # 自己走
def main():
    signal.signal(signal.SIGINT, handler) # Ctrl-c
    # time.sleep(10) # SIGINT 信号同样能唤醒 time.sleep, 所以这里程序就会结束
    while True: # 改成 while 效果会好点
       pass
if __name__ == '__main__':
    main()
再看看SIGTERM的效果
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
    当我们运行该程序时因为 while True 所以会持续的运行.
    这里监听的是 SIGTERM 信号, 所以当我们在终端输入 kill pid (linux kill
    默认是发送SIGTERM)时,
    程序就会输出: 收到信号 15 <frame object at 0x7ff695738050> 0
    当超过3次时就强制把自己杀死.
    所以 SIGTERM 很适合用来做一些清理的工作
"""
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
import time
import os
import signal
receive_times = 0
def handler(signalnum, frame):
    global receive_times
    print u"收到信号", signalnum, frame, receive_times
    receive_times += 1
    if receive_times > 3:
        exit(0) # 自己走
def main():
    print "pid:", os.getpid()
    signal.signal(signal.SIGTERM, handler)
    while True:
        pass
if __name__ == '__main__':
    main()
刚才我们说过SIGKILL不能被监听.
signal.signal(signal.SIGKILL, handler)
# 这里系统会直接跑错 AttributeError: 'module' object has no attribute 'SIGKILL'
最后来一个实际运用的例子
在python2.x的版本, 线程有个bug, 在join的时候不能接收信号
详解见:https://bugs.python.org/issue1167930
所以如果我们运行以下代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
    这里虽然我们监听了 SIGINT 信号, 但是当我们按下Ctrl-c时程序并没有任何输出. 还是要等线程运行完成程序才退出.
"""
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
import time
import os
import signal
import threading
receive_times = 0
def handler(signalnum, frame):
    global receive_times
    print u"收到信号", signalnum, frame, receive_times
    receive_times += 1
    if receive_times > 3:
        # os.kill(os.getpid(), signal.SIGTERM) # 我疯起来连自己都杀
        exit(0)
def run():
    print "thread %s run:"%(threading.currentThread().getName())
    time.sleep(10)
    print "thread %s done"%(threading.currentThread().getName())
def main():
    print "pid:", os.getpid()
    signal.signal(signal.SIGINT, handler)
    thread_list = []
    for i in range(5):
        thread = threading.Thread(target = run)
        thread_list.append(thread)
    for thread in thread_list:
        thread.start()
    for thread in thread_list:
        thread.join()
    print "all thread done"
if __name__ == '__main__':
    main()
然后我们来改一下
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
    在这里我们放弃了线程的join() 方法, 然后用 while True 的方式来代替, 然后在主进程判断线程的存活状态. 这样既能持续的运行线程又能根据需求来随时中断
"""
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
import time
import os
import signal
import threading
is_run_thread = True
def handler(signalnum, frame):
    print u"收到信号", signalnum, frame
    global is_run_thread
    is_run_thread = False # 停止运行线程
def run():
    print "thread %s run:"%(threading.currentThread().getName())
    while is_run_thread:
        # do something
        pass
    print "thread %s done"%(threading.currentThread().getName())
def main():
    print "pid:", os.getpid()
    signal.signal(signal.SIGINT, handler)
    thread_list = []
    for i in range(5):
        thread = threading.Thread(target = run)
        thread_list.append(thread)
    for thread in thread_list:
        thread.start()
   # 注意这里
    while True:
        for thread in thread_list:
            if thread.isAlive():
                break
        else:
            break
    # for thread in thread_list:
    #     thread.join()
    print "all thread done"
if __name__ == '__main__':
    main()
注意, 在wnidows系统中只能调用 SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, or SIGTERM
Python和Signal的更多相关文章
- Python使用signal模块实现定时执行
		
在liunx系统中要想每隔一分钟执行一个命令,最普遍的方法就是crontab了,如果不想使用crontab,经同事指点在程序中可以用定时器实现这种功能,于是就开始摸索了,发现需要一些信号的知识... ...
 - Python 信号处理 signal 模块
		
Table of Contents 1. signal模块简介 1.1. signal简单示例 1.2. signal说明 1.2.1. 基本的信号名 1.2.2. 常用信号处理函数 2. signa ...
 - matlab与python scipy.signal中 freqs freqz 中w,什么时候是角频率,什么时候是真实的工程中使用的采样频率Hz,如何转化
		
matlab与python scipy.signal中的freqs,freqz频率分析函数,输出的w,有时候是角频率,有时候是真实频率,容易搞混,这里对比一下. 0. 精要总结: 1) freqs: ...
 - python信号signal简单示例
		
进程间通信之类的,用得着, 可以自定义接到信息之后的动作. file1.py #!/usr/bin/env python # -*- coding: utf-8 -*- import os impor ...
 - Python之signal模块的使用
		
常用的信号值如下: 信号值 事件 处理方式 SIGHUP 终止进程 终端线路挂断 SIGINT 终止进程 中断进程 SIGQUIT "建立CORE文件终止进程,并且生成core文件" ...
 - Python之signal模块
		
http://www.cnblogs.com/dkblog/archive/2011/03/07/1980636.html 1.超时处理 #!/usr/bin/env python2.7 #-*- c ...
 - 转:python signal信号
		
转自:http://www.jb51.net/article/74844.htm 在liunx系统中要想每隔一分钟执行一个命令,最普遍的方法就是crontab了,如果不想使用crontab,经同事指点 ...
 - Python——signal
		
该模块为在Python中使用信号处理句柄提供支持.下面是一些使用信号和他们的句柄时需要注意的事项: 除了信号 SIGCHLD 的句柄遵从底层的实现外,专门针对一个信号的句柄一旦设置,除非被明确地重置, ...
 - python学习笔记——信号模块signal
		
基于python学习笔记——多进程间通信——Linux信号基础的学习基础,进一步学习Python标准库中的signal模块. 尽管signal是python中的模块,但是主要针对UNIX平台(比如Li ...
 
随机推荐
- hdu2079 选课时间(题目已修改,注意读题) 母函数
			
计算数的和的种类,母函数裸题 #include<stdio.h> #include<string.h> ],c2[],a,b; int main(){ int T; while ...
 - 关于jdbc的面试题
			
什么是JDBC,在什么时候会用到它? JDBC的全称是Java DataBase Connection,也就是Java数据库连接,我们可以用它来操作关系型数据库.JDBC接口及相关类在java.sql ...
 - 2018第52周日&技术人员如何面对裁员?
			
2018的最后一周,看了汽车的两个趋势,纯电动车和自动驾驶,两个现在很火但还有很多问题要解决的方向,尤其是自动驾驶.虽然它因为一些问题当前不能完全被克服,但因它而生的各种辅助驾驶技术却被用的越来越多, ...
 - java 设计模式:单例模式
			
Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建自己的唯 ...
 - shell获取目录下所有文件夹的名称并输出
			
获取指定目录/usr/下所有文件夹的名称并输出: shell代码: #!/bin/bash #方法一 dir=$(ls -l /usr/ |awk '/^d/ {print $NF}') for i ...
 - spark内存模型
			
在spark里面,内存管理有两块组成,一部分是JVM的堆内内存(on-heap memory),这部分内存是通过spark dirver参数executor-memory以及spark.executo ...
 - 【linux】vim/vi常用指令
			
0或者"Home”键:光标转移到此段的最前面字节处. $或者"End"键:光标转移到此段的最后面字节处. n<space>:光标向后移动n个字节. n< ...
 - win7 配置微软的深度学习caffe
			
win7 配置微软的深度学习caffe 官方下载: https://github.com/Microsoft/caffe 然后 直接修改caffe目录下的windows目录下的项目的props文件 ...
 - 使用纯生js操作cookie
			
前段时间做项目的时候要使用js操作cookie,jquery也有相应的插件,不过还是觉得纯生的js比较好,毕竟不依赖jq. //获得coolie 的值 function cookie(name) { ...
 - phonegap 2.9 IOS Xcode 搭建环境
			
一:下载phoneGap2.9和安装Xcode5(目前最新版) 选择2.9是因为3.0以上坑爹版本编译神马的要在有网络情况. 二: 下载phonegap后解压到你的指定文件夹中,解压后找到create ...