Python:如何终止一个阻塞线程

4 投票
2 回答
26792 浏览
提问于 2025-04-16 11:56

可能重复的问题:
在Python中有没有办法终止一个线程?

这个问题是对之前一个解决方案的后续提问。基本上,它讨论的是如何通过编程的方式终止一个线程:http://sebulba.wikispaces.com/recipe+thread2

不过这个方法并没有奏效……我想知道有没有人能解释一下,如何终止一个正在阻塞的线程?我猜测可能是因为我没有提供正确的线程ID,但我做了一些测试,觉得我应该可以直接使用iden。

如果真的是线程ID的问题,那我该如何获取正确的线程ID呢?

测试代码:

class BlockingTestThread(Thread):

    def __init__(self):
        self._running_flag = False
        Thread.__init__(self, target=self.test_method)

    def test_method(self):
        try:
            while(not self.stopped()):
                self._running_flag = True
                time.sleep(100)
        finally:
                self._running_flag = False


def _async_raise(tid, exctype):
    '''Raises an exception in the threads with id tid'''
    if not inspect.isclass(exctype):
        raise TypeError("Only types can be raised (not instances)")

    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid), ctypes.py_object(exctype))
    time.sleep(0.1)



if __name__ == "__main__":
    thread = BlockingTestThread()
    thread.start()

    _async_raise(thread.ident, SystemExit)
    print "Joining thread"
    thread.join()
    print "Done Joining thread"
    #will never get here!

2 个回答

0

你说得对,关于ident这个变量,从文档来看,它并不是线程的ID,而只是一个引用。

thread.get_ident()

这个函数会返回当前线程的“线程标识符”。它是一个非零的整数。这个值本身没有特别的意义;它主要是用来作为一个“魔法饼干”,比如用来在一个字典中查找与线程相关的数据。当一个线程结束后,可能会重新使用这个线程标识符给新创建的线程。

关于终止线程的内容,可以参考这个链接:http://bytes.com/topic/python/answers/45247-terminating-thread-parent,不过我不太确定这是否正是你想要的。

3

这里有个更好的方法,就是在事件上使用“wait”命令,假设你想用睡眠功能。

class BlockingTestThread(Thread):
    def __init__(self):
        self._running_flag = False
        self.stop  = threading.Event()
        Thread.__init__(self, target=self.test_method)

    def test_method(self):
        try:
            while(not self.stop.wait(1)):
                self._running_flag = True
                print 'Start wait'
                self.stop.wait(100)
                print 'Done waiting'
        finally:
                self._running_flag = False

    def terminate(self):
         self.stop.set()  

if __name__ == "__main__":
    thread = BlockingTestThread()
    thread.start()

    time.sleep(2)
    print 'Time sleep 2'
    thread.terminate()
    print "Joining thread"
    thread.join()
    print "Done Joining thread"

显然,你需要把你的阻塞线程放在上面提到的模式中,但如果你做不到,另一种选择就是让你的程序抛出一个异常。在我们的例子中,我们基本上是关闭了底层连接,这样就会产生一个异常。当这个异常发生时,如果停止标志被设置,我们就会忽略它。

撰写回答