Python在多线程程序中忽略SIGINT - 如何解决?

3 投票
3 回答
2226 浏览
提问于 2025-04-16 06:05

我在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 个回答

2

我对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 就可以了。

2

你可能根本不需要用到线程。

可以试试使用Python的 subprocess 模块,或者甚至可以看看Twisted的 进程支持

2

可能导致你遇到问题的几个原因:

  1. 你按的 Ctrl-C 可能被 svn 捕捉到了,而它并没有理会这个指令。
  2. 你创建了一个非守护线程,然后直接退出了程序。这样会导致程序一直等着这个线程结束,但它永远不会结束。你需要把这个线程设置为守护线程,或者给它一个结束的办法,并在退出之前调用 join() 来等待它结束。虽然在我的 Linux 系统上总是能正常停止,但在 MacOS X 上可能表现不同。

Python 和线程的配合还是挺不错的 :-)

更新:你可以试试使用 subprocess,设置子进程,使得文件句柄不会被继承,并把子进程的标准输入设置为 subprocess.PIPE。

撰写回答