python多线程程序的中断(信号)处理

python程序很容易进行多线程处理,也很好进行signal的处理。但是,在多线程程序中进行信号处理,却不太好搞。我琢磨出了一个可行的办法。
看第一个程序:singlethread.py

#!/usr/bin/python
#coding:utf-8

import signal,os,sys,threading,time
import wk
def sig_exit():
    print "[end time]:"+str(time.time())
    print "exited."
    sys.exit()

def handler(signum, frame):
    print "got an signal",signum,frame
    if signum == 3:
        sig_exit()
    if signum == 2:
        sig_exit()
    if signum == 9:
        sig_exit()
        return None
signal.signal(signal.SIGINT,handler)
signal.signal(signal.SIGTERM,handler)
signal.signal(3,handler)

TIME=3

time.sleep(TIME)
print 'normally exit'

运行这个程序,并马上按上Ctrl+C,发现程序这样输出:
<pre>
^Cgot an signal 2
[end time]:1245852618.36
exited.

而不做干扰,让它正常退出时,是这样的:

  1. normally exit

现在我们改进到多线程版本。先写一个线程类:wk.py

  1. import threading,time
  2. class wk(threading.Thread):
  3.     def run(self):
  4.         for k in xrange(0,4):
  5.             print 'sleep 1 second,',self,":",k
  6.             time.sleep(1)

这个线程类啥也不干,就不断输出一个标识 ,然后再歇一秒。再输出,再歇一秒....
主程序:multithreads.py

  1. #!/usr/bin/python
  2. #coding:utf-8
  3.  
  4. import signal,os,sys,threading,time
  5. from wk import wk
  6.  
  7. def sig_exit():
  8.     print "[end time]:"+str(time.time())
  9.     print "exited."
  10.     sys.exit()
  11.  
  12. def handler(signum, frame):
  13.     print "got an signal",signum,frame
  14.     sig_exit()
  15.     if signum == 3:
  16.         sig_exit()
  17.     if signum == 2:
  18.         sig_exit()
  19.     if signum == 9:
  20.         sig_exit()
  21.         return None
  22. signal.signal(signal.SIGINT,handler)
  23. signal.signal(signal.SIGTERM,handler)
  24. signal.signal(3,handler)
  25. signal.signal(signal.SIGALRM, handler)
  26.  
  27.  
  28.  
  29.  
  30.  
  31. threads=[]
  32. for a in xrange(0,4):
  33.     temp=wk()
  34.     temp.setDaemon(True)
  35.     temp.setName("thread:"+str(a))
  36.     temp.start()
  37.     threads.append(temp)
  38.  
  39. for thread in threads:
  40.     thread.join()
  41.     print "thread joined",thread
  42.  
  43. print 'normally exit'

现在我们运行它,并按下CTL+C.输出结果像这样:

  1. sleep 1 second,sleep 1 second, <wk(thread:1, started daemon -1218901104)> : 0
  2.  sleep 1 second, <wk(thread:2, started daemon -1227293808)> : 0
  3.  <wk(thread:0, started daemon -1210508400)> : 0
  4.  sleep 1 second, <wk(thread:3, started daemon -1235686512)> : 0
  5. sleep 1 second, <wk(thread:2, started daemon -1227293808)> : 1
  6. sleep 1 second, <wk(thread:0, started daemon -1210508400)> : 1
  7. sleep 1 second, <wk(thread:1, started daemon -1218901104)> : 1
  8. sleep 1 second, <wk(thread:3, started daemon -1235686512)> : 1
  9. ^Csleep 1 second, <wk(thread:0, started daemon -1210508400)> : 2
  10. sleep 1 second, <wk(thread:1, started daemon -1218901104)> : 2
  11. sleep 1 second, <wk(thread:3, started daemon -1235686512)> : 2
  12. sleep 1 second, <wk(thread:2, started daemon -1227293808)> : 2
  13. ^Csleep 1 second, <wk(thread:0, started daemon -1210508400)> : 3
  14. sleep 1 second, <wk(thread:1, started daemon -1218901104)> : 3
  15. sleep 1 second, <wk(thread:3, started daemon -1235686512)> : 3
  16. sleep 1 second, <wk(thread:2, started daemon -1227293808)> : 3
  17. got an signal 2 <frame object at 0x8afc87c>
  18. [end time]:1245852879.37
  19. exited.

在按下CTRL+C后,程序并不是马上退出,而是又过了几秒钟才退出。
而运行时不按CTRL+C干扰它时,是这样的输出:

sleep 1 second, : 0
sleep 1 second, : 0
sleep 1 second, : 0
sleep 1 second, : 0
sleep 1 second, : 1
sleep 1 second, : 1
sleep 1 second, : 1
sleep 1 second, : 1
sleep 1 second, : 2
sleep 1 second, : 2
sleep 1 second, : 2
sleep 1 second, : 2
sleep 1 second, : 3
sleep 1 second, : 3
sleep 1 second, : 3
sleep 1 second, : 3
thread joined
thread joined
thread joined
thread joined
normally exit
</coolcode>
说明在这个程序里,中断信号能被捕获,但是并不即时。

而最后我的多线程程序是:last.py

#!/usr/bin/python
#coding:utf-8

import signal,os,sys,threading,time
from wk import wk

def sig_exit():
print "[end time]:"+str(time.time())
print "exited."
sys.exit()

def handler(signum, frame):
print "got an signal",signum,frame
if signum == 3:
sig_exit()
if signum == 2:
sig_exit()
if signum == 9:
sig_exit()
return None
signal.signal(signal.SIGINT,handler)
signal.signal(signal.SIGTERM,handler)
#signal.signal(3,handler)
signal.signal(signal.SIGALRM, handler)

class pause(threading.Thread):
threads=[]
def run(self):
print "pause running"
for thread in self.threads:
thread.join()
print "thread ",thread," joined"
print "all joined"
signal.alarm(1)

threads=[]
for i in xrange(0,4):
j=wk()
j.setDaemon(True)
j.setName("thread:"+str(i))
j.start()
threads.append(j)
print "total threads:",threading.activeCount()

print "current thread:",threading.activeCount()
print "parent process,main thread,sleeping"

k=pause()
k.setDaemon(True)
k.threads=threads
k.start()
signal.pause()
print "normally exit"

这个程序里,我们的逻辑是这样的:主线程创建了其他工作线程,并且还创建了一个特殊的线程, 这个特殊的线程的任务就着等着其他的工作线程结束(调用了wk类的join方法)。当工作线程都结束后,这个线程就发一个alarm信号。而主线程创建完所有的其他线程后的工作,就是在坐在那儿专门等一个信号。因此当我们按CTRL+C时信号就成功地被捕获了。而没有CTRL+C产生的信号被捕获时,所有工作线程(wk类)结束时也会产生一个alarm信号,也能让程序顺利退出。
这个程序,运行时按下CTRL+C的输出是:

sleep 1 second, : 0
total threads: 2
sleep 1 second, : 0
total threads: 3
sleep 1 second, : 0
total threads: 4
sleep 1 second, : 0
total threads: 5
current thread: 5
parent process,main thread,sleeping
pause running
^Cgot an signal 2
[end time]:1245853073.05
exited.

CTRL+C给程序的信号马上得到了处理。运行这个程序时啥也不做,等着程序结束,输出则是:

sleep 1 second, : 0
total threads: 2
sleep 1 second, : 0
total threads: 3
sleep 1 second, : 0
total threads: 4
sleep 1 second, : 0
total threads: 5
current thread: 5
parent process,main thread,sleeping
pause running
^Cgot an signal 2
[end time]:1245853073.05
exited.
renlu@aragorn:~/Dropbox/Private/devel/python$ py lastprogram.py
sleep 1 second, total threads: : 0
2
sleep 1 second, : 0
total threads: 3
sleep 1 second, : 0
total threads: 4
sleep 1 second, : 0
total threads: 5
current thread: 5
parent process,main thread,sleeping
pause running
sleep 1 second, : 1
sleep 1 second, : 1
sleep 1 second, : 1
sleep 1 second, : 1
sleep 1 second, sleep 1 second, : 2
: 2
sleep 1 second, : 2
sleep 1 second, : 2
sleep 1 second, : 3
sleep 1 second, : 3
sleep 1 second, : 3
sleep 1 second, : 3
thread joined
thread joined
thread joined
thread joined
all joined
got an signal 14
normally exit


本文由蝌蚪安尼友情赞助.
相关文章
此条目发表在 python 分类目录,贴了 , , 标签。将固定链接加入收藏夹。

发表评论

电子邮件地址不会被公开。 必填项已被标记为 *

*

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>