Python在多线程程序中忽略SIGINT - 如何解决?
我在MacOS X上使用的是Python 2.6,并且有一个多线程的操作。下面这段测试代码运行得很好,当我按下Ctrl-C时,应用程序会正常关闭:
import threading, time, os, sys, signal
def SigIntHandler( signum, frame ) :
sys.exit( 0 )
signal.signal( signal.SIGINT, SigIntHandler )
class WorkThread( threading.Thread ) :
def run( self ) :
while True :
time.sleep( 1 )
thread = WorkThread()
thread.start()
time.sleep( 1000 )
但是如果我只改动了一行字符串,给工作线程添加了一些实际的工作,这样一来,应用程序在按下Ctrl-C时就永远不会结束了:
import threading, time, os, sys, signal
def SigIntHandler( signum, frame ) :
sys.exit( 0 )
signal.signal( signal.SIGINT, SigIntHandler )
class WorkThread( threading.Thread ) :
def run( self ) :
while True :
os.system( "svn up" ) # This is really slow and can fail.
time.sleep( 1 )
thread = WorkThread()
thread.start()
time.sleep( 1000 )
这有没有办法解决呢?还是说Python本身就不适合用来做多线程?
3 个回答
我对Python中的线程不是很专业,但快速浏览了一下文档后,有几个结论。
1) 调用 os.system()
会启动一个新的子shell,这种做法不太推荐。更好的选择是使用子进程模块。http://docs.python.org/release/2.6.6/library/os.html?highlight=os.system#os.system
2) threading
模块似乎对线程的控制不太多,可能可以尝试使用 thread
模块,至少它有一个 thread.exit()
函数。此外,从 threading
的文档 这里 看到,可能会创建一些虚拟线程,这些线程总是活着并且是守护线程。
"… the entire Python program exits when only daemon threads are left."
所以,我想你至少需要做的是在退出主线程之前,给当前正在运行的线程发信号,让它们知道需要退出,或者在按下ctrl-c时让它们完成(虽然这显然和ctrl-c是矛盾的),或者也许只是使用 subprocess
模块来启动 svn up
就可以了。
你可能根本不需要用到线程。
可以试试使用Python的 subprocess
模块,或者甚至可以看看Twisted的 进程支持。
可能导致你遇到问题的几个原因:
- 你按的 Ctrl-C 可能被
svn
捕捉到了,而它并没有理会这个指令。 - 你创建了一个非守护线程,然后直接退出了程序。这样会导致程序一直等着这个线程结束,但它永远不会结束。你需要把这个线程设置为守护线程,或者给它一个结束的办法,并在退出之前调用
join()
来等待它结束。虽然在我的 Linux 系统上总是能正常停止,但在 MacOS X 上可能表现不同。
Python 和线程的配合还是挺不错的 :-)
更新:你可以试试使用 subprocess
,设置子进程,使得文件句柄不会被继承,并把子进程的标准输入设置为 subprocess.PIPE。