»
S
I
D
E
B
A
R
«
python多线程程序的中断(信号)处理
June 24th, 2009 by 一米六二

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.

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

normally exit

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

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

这个线程类啥也不干,就不断输出一个标识 ,然后再歇一秒。再输出,再歇一秒....
主程序:multithreads.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
sig_exit()
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)

threads=[]
for a in xrange(0,4):
temp=wk()
temp.setDaemon(True)
temp.setName("thread:"+str(a))
temp.start()
threads.append(temp)

for thread in threads:
thread.join()
print "thread joined",thread

print 'normally exit'

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

sleep 1 second,sleep 1 second, : 0
sleep 1 second, : 0
: 0
sleep 1 second, : 0
sleep 1 second, : 1
sleep 1 second, : 1
sleep 1 second, : 1
sleep 1 second, : 1
^Csleep 1 second, : 2
sleep 1 second, : 2
sleep 1 second, : 2
sleep 1 second, : 2
^Csleep 1 second, : 3
sleep 1 second, : 3
sleep 1 second, : 3
sleep 1 second, : 3
got an signal 2
[end time]:1245852879.37
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


Leave a Reply

»  Substance: WordPress   »  Style: Ahren Ahimsa
28299 页面访问次数, 470 今天
11033 访问数, 170 今天
FireStats icon 由FireStats提供支持