初步理解Python进程的信号通讯_python

信号的概念

信号(signal)--     进程之间通讯的方式,是一种软件中断。一个进程一旦接收到信号就会打断原来的程序执行流程来处理信号。

几个常用信号:

SIGINT     终止进程  中断进程  (control+c)

SIGTERM   终止进程     软件终止信号

SIGKILL   终止进程     杀死进程

SIGALRM 闹钟信号
进程结束信号 SIGTERM和SIGKILL的区别

SIGTERM比较友好,进程能捕捉这个信号,根据您的需要来关闭程序。在关闭程序之前,您可以结束打开的记录文件和完成正在做的任务。在某些情况下,假如进程正在进行作业而且不能中断,那么进程可以忽略这个SIGTERM信号。

对于SIGKILL信号,进程是不能忽略的。这是一个 “我不管您在做什么,立刻停止”的信号。假如您发送SIGKILL信号给进程,Linux就将进程停止在那里。
发送信号一般有两种原因:

1(被动式)  内核检测到一个系统事件.例如子进程退出会像父进程发送SIGCHLD信号.键盘按下control+c会发送SIGINT信号

2(主动式)  通过系统调用kill来向指定进程发送信号
linux操作系统提供的信号

[100003@oss235 myppt]$ kill -l

 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL

 5) SIGTRAP      6) 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

Python提供的信号

Python 2.4.3 (#1, Jun 11 2009, 14:09:58)

[GCC 4.1.2 20080704 (Red Hat 4.1.2-44)] on linux2

Type "help", "copyright", "credits" or "license" for more information.

>>> import signal

>>> dir(signal)

['NSIG', 'SIGABRT', 'SIGALRM', 'SIGBUS', 'SIGCHLD', 'SIGCLD', 'SIGCONT', 'SIGFPE', 'SIGHUP', 'SIGILL', 'SIGINT', 'SIGIO', 'SIGIOT', 'SIGKILL', 'SIGPIPE', 'SIGPOLL', 'SIGPROF', 'SIGPWR', 'SIGQUIT', 'SIGRTMAX', 'SIGRTMIN', 'SIGSEGV', 'SIGSTOP', 'SIGSYS', 'SIGTERM', 'SIGTRAP', 'SIGTSTP', 'SIGTTIN', 'SIGTTOU', 'SIGURG', 'SIGUSR1', 'SIGUSR2', 'SIGVTALRM', 'SIGWINCH', 'SIGXCPU', 'SIGXFSZ', 'SIG_DFL', 'SIG_IGN', '__doc__', '__name__', 'alarm', 'default_int_handler', 'getsignal', 'pause', 'signal']

操作系统规定了进程收到信号以后的默认行为

但是,我们可以通过绑定信号处理函数来修改进程收到信号以后的行为

有两个信号是不可更改的SIGTOP和SIGKILL
绑定信号处理函数

  import os
  import signal
  from time import sleep  

  def onsignal_term(a,b):
    print '收到SIGTERM信号'  

  #这里是绑定信号处理函数,将SIGTERM绑定在函数onsignal_term上面
  signal.signal(signal.SIGTERM,onsignal_term)  

  def onsignal_usr1(a,b):
    print '收到SIGUSR1信号'
  #这里是绑定信号处理函数,将SIGUSR1绑定在函数onsignal_term上面
  signal.signal(signal.SIGUSR1,onsignal_usr1)  

  while 1:
    print '我的进程id是',os.getpid()
    sleep(10)  

运行该程序。然后通过另外一个进程来发送信号。
发送信号

发送信号的代码如下:

  import os
  import signal  

  #发送信号,16175是前面那个绑定信号处理函数的pid,需要自行修改
  os.kill(16175,signal.SIGTERM)
  #发送信号,16175是前面那个绑定信号处理函数的pid,需要自行修改
  os.kill(16175,signal.SIGUSR1)  

SIGCHLD信号

然后显示一个子进程结束后自动向父进程发送SIGCHLD信号的例子。

  '''''''
  子进程结束会向父进程发送SIGCHLD信号
  '''
  import os
  import signal
  from time import sleep  

  def onsigchld(a,b):
    print '收到子进程结束信号'
  signal.signal(signal.SIGCHLD,onsigchld)  

  pid = os.fork()
  if pid == 0:
    print '我是子进程,pid是',os.getpid()
    sleep(2)
  else:
    print '我是父进程,pid是',os.getpid()
    os.wait() #等待子进程结束  

使用信号需要特别注意的地方:

如果一个进程收到一个SIGUSR1信号,然后执行信号绑定函数,第二个SIGUSR2信号又来了,第一个信号没有被处理完毕的话,第二个信号就会丢弃。

所以,尽量不要在多线程中使用信号。

这个不妥,测试没发现有信号丢失

例子演示:

接收信号的程序,你会发现如果有另外一端使用多线程向这个进程发送信号,会遗漏一些信号。

  import os
  import signal
  from time import sleep
  import Queue  

  QCOUNT = Queue.Queue() #初始化队列  

  def onsigchld(a,b):
    '''''''收到信号后向队列中插入一个数字1'''
    print '收到SIGUSR1信号'
    sleep(2)
    QCOUNT.put(1) #向队列中写入  

  def exithanddle(s,e):
    raise SystemExit('收到终止命令,退出程序')  

  signal.signal(signal.SIGUSR1,onsigchld) #绑定信号处理函数
  signal.signal(signal.SIGINT,exithanddle) #当按下Ctrl + C 终止进程 

  while 1:
    print '我的pid是',os.getpid()
    print '现在队列中元素的个数是',QCOUNT.qsize()
    sleep(2) 

多线程发信号端的程序:

 

  '''''''
  使用多线程向另外一个进程发送信号
  '''
  import threading
  import os
  import signal  

  def sendusr1():
    print '发送信号'
    #这里的进程id需要写前一个程序实际运行的pid
    os.kill(17788, signal.SIGUSR1)  

  WORKER = []  

  #开启6个线程
  for i in range(1, 7):
    threadinstance = threading.Thread(target = sendusr1)
    WORKER.append(threadinstance)  

  for i in WORKER:
    i.start()  

  for i in WORKER:
    i.join()  

  print '主线程完成'

内容补充:

Alarms 是一个特殊信号类型,它可以让程序要求系统经过一段时间对自己发送通知。os 标准模块中指出,它可用于避免无限制阻塞 I/O 操作或其它系统调用。

像下面例子,原本程序睡眠 10 后才打印出 print 'After :', time.ctime(),但是由于 signal.alarm(2),所以 2 秒后就执行了打印。

  import signal
  import time 

  def receive_alarm(signum, stack):
    print 'Alarm :', time.ctime() 

  # Call receive_alarm in 2 seconds
  signal.signal(signal.SIGALRM, receive_alarm)
  signal.alarm(2) 

  print 'Before:', time.ctime()
  time.sleep(10)
  print 'After :', time.ctime()  

注意Signal只有主线程才能接收信号,像下面例子,print 'Done waiting' 语句打印不出来,如果不调用 signal.alarm(2) ,程序将永远阻塞

  import signal
  import threading
  import os
  import time 

  def signal_handler(num, stack):
    print 'Received signal %d in %s' % \
      (num, threading.currentThread().name) 

  signal.signal(signal.SIGUSR1, signal_handler) 

  def wait_for_signal():
    print 'Waiting for signal in', threading.currentThread().name
    signal.pause()
    print 'Done waiting' 

  # Start a thread that will not receive the signal
  receiver = threading.Thread(target=wait_for_signal, name='receiver')
  receiver.start()
  time.sleep(0.1) 

  def send_signal():
    print 'Sending signal in', threading.currentThread().name
    os.kill(os.getpid(), signal.SIGUSR1) 

  sender = threading.Thread(target=send_signal, name='sender')
  sender.start()
  sender.join() 

  # Wait for the thread to see the signal (not going to happen!)
  print 'Waiting for', receiver.name
  signal.alarm(2)
  receiver.join() 

还有一点需要注意的是,虽然 alarms 类信号可以在任何线程中调用,但是只能在主线程中接收,像下面例子即使子线程 use_alarm 中调用  signal.alarm(1) ,但是不起作用 :

  import signal
  import time
  import threading 

  def signal_handler(num, stack):
    print time.ctime(), 'Alarm in', threading.currentThread().name 

  signal.signal(signal.SIGALRM, signal_handler) 

  def use_alarm():
    t_name = threading.currentThread().name
    print time.ctime(), 'Setting alarm in', t_name
    signal.alarm(1)
    print time.ctime(), 'Sleeping in', t_name
    time.sleep(3)
    print time.ctime(), 'Done with sleep in', t_name 

  # Start a thread that will not receive the signal
  alarm_thread = threading.Thread(target=use_alarm,
                  name='alarm_thread')
  alarm_thread.start()
  time.sleep(0.1) 

  # Wait for the thread to see the signal (not going to happen!)
  print time.ctime(), 'Waiting for', alarm_thread.name
  alarm_thread.join() 

  print time.ctime(), 'Exiting normally' 

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索python
python 进程间通讯、python 进程通讯、android 进程间通讯、android 跨进程通讯、进程通讯,以便于您获取更多的相关知识。

时间: 2025-01-29 07:25:30

初步理解Python进程的信号通讯_python的相关文章

深入Python解释器理解Python中的字节码_python

我最近在参与Python字节码相关的工作,想与大家分享一些这方面的经验.更准确的说,我正在参与2.6到2.7版本的CPython解释器字节码的工作. Python是一门动态语言,在命令行工具下运行时,本质上执行了下面的步骤:     当第一次执行到一段代码时,这段代码会被编译(如,作为一个模块加载,或者直接执行).根据操作系统的不同,这一步生成后缀名是pyc或者pyo的二进制文件.     解释器读取二进制文件,并依次执行指令(opcodes). Python解释器是基于栈的.要理解数据流向,我

初步探究Python程序的执行原理_python

1. 过程概述 Python先把代码(.py文件)编译成字节码,交给字节码虚拟机,然后虚拟机一条一条执行字节码指令,从而完成程序的执行.2. 字节码 字节码在Python虚拟机程序里对应的是PyCodeObject对象. .pyc文件是字节码在磁盘上的表现形式.3. pyc文件 PyCodeObject对象的创建时机是模块加载的时候,即import. Python test.py会对test.py进行编译成字节码并解释执行,但是不会生成test.pyc. 如果test.py加载了其他模块,如im

理解Python中的With语句_python

With语句是什么? 有一些任务,可能事先需要设置,事后做清理工作.对于这种场景,Python的with语句提供了一种非常方便的处理方式.一个很好的例子是文件处理,你需要获取一个文件句柄,从文件中读取数据,然后关闭文件句柄. 如果不用with语句,代码如下: 复制代码 代码如下: file = open("/tmp/foo.txt") data = file.read() file.close() 这里有两个问题.一是可能忘记关闭文件句柄:二是文件读取数据发生异常,没有进行任何处理.下

理解Python中函数的参数_python

 定义函数的时候,我们把参数的名字和位置确定下来,函数的接口定义就完成了.对于函数的调用者来说,只需要知道如何传递正确的参数,以及函数将返回什么样的值就够了,函数内部的复杂逻辑被封装起来,调用者无需了解. Python的函数定义非常简单,但灵活度却非常大.除了正常定义的必选参数外,还可以使用默认参数.可变参数和关键字参数,使得函数定义出来的接口,不但能处理复杂的参数,还可以简化调用者的代码.默认参数 我们仍以具体的例子来说明如何定义函数的默认参数.先写一个计算x2的函数: def power(x

Python简单进程锁代码实例_python

先说说线程 在多线程中,为了保证共享资源的正确性,我们常常会用到线程同步技术. 将一些敏感操作变成原子操作,保证同一时刻多个线程中只有一个线程在执行这个原子操作. 我最常用的是互斥锁,也称独占锁.其次还有读写锁,信号量,条件变量等. 除此之外,我们在进程间通信时会用到信号,向某一个进程发送信号,该进程中设置信号处理函数,然后当该进程收到信号时,执行某些操作. 其实在线程中,也可以接受信号,利用这种机制,我们也可以用来实现线程同步.更多信息见 http://www.jb51.net/article

如何实现进程间数据通讯技术

1.引言 在Windows程序中,各个进程之间常常需要交换数据,进行数据通讯.WIN32 API提供了许多函数使我们能够方便高效地进行进程间的通讯,通过这些函数我们可以控制不同进程间的数据交换,就如同在WIN16中对本地进程进行读写操作一样. 典型的WIN16两进程可以通过共享内存来进行数据交换:(1)进程A将GlobalAlloc(GMEM_SHARE...)API分配一定长度的内存:(2)进程A将GlobalAlloc函数返回的句柄传递给进程B(通过一个登录消息):(3)进程B对这个句柄调用

2信号处理之:信号产生原因,进程处理信号行为,信号集处理函数,PCB的信号集,sigprocmask()和sigpending(),信号捕捉设定,sigaction,C标准库信号处理函数,可重入函数,

 1信号产生原因 2.进程处理信号行为 manpage里信号3中处理方式: SIG_IGN SIG_DFL                                            默认Term动作 a signal handling function 进程处理信号 A默认处理动作 term   中断 core    core(调试的时候产生) gcc –g file.c     ulimit –c 1024     gdb a.out core ign      忽略 stop

深入理解Python中的ThreadLocal变量(下)

在上篇我们看到了 ThreadLocal 变量的简单使用,中篇对python中 ThreadLocal 的实现进行了分析,但故事还没有结束.本篇我们一起来看下Werkzeug中ThreadLocal的设计. Werkzeug 作为一个 WSGI 工具库,由于一些方面的考虑,并没有直接使用python内置的ThreadLocal类,而是自己实现了一系列Local类.包括简单的Local,以及在此基础上实现的LocalStack,LocalManager 和 LocalProxy.接下来我们一起来看

深入理解Python中的ThreadLocal变量(中)

在 深入理解Python中的ThreadLocal变量(上)中我们看到 ThreadLocal 的引入,使得可以很方便地在多线程环境中使用局部变量.如此美妙的功能到底是怎样实现的?如果你对它的实现原理没有好奇心或一探究竟的冲动,那么接下来的内容估计会让你后悔自己的浅尝辄止了. 简单来说,Python 中 ThreadLocal 就是通过下图中的方法,将全局变量伪装成线程局部变量,相信读完本篇文章你会理解图中内容的.(对这张图不眼熟的话,可以回顾下上篇)). 在哪里找到源码? 好了,终于要来分析