如何在Python中终止一个线程

13
我使用以下代码启动一个线程。
t = thread.start_new_thread(myfunction)

如何从另一个线程杀死线程t。简单来说,我想要做的事情就是这样的。请看下面的代码:
t.kill()

请注意,我正在使用Python 2.4版本。

1
请问为什么您使用低级别的thread模块而不是高级别的threading库? - Niklas R
3个回答

30

在Python中,你无法直接终止一个线程。

如果你实际上不需要使用线程,而是使用multiprocessing包(http://docs.python.org/2/library/multiprocessing.html)替代threading包(http://docs.python.org/2/library/threading.html),那么你可以通过调用以下方法来终止一个进程:

yourProcess.terminate()  # kill the process!

Python会通过SIGTERM信号(在Unix上)或TerminateProcess()调用(在Windows上)来终止进程。在使用Queue或Pipe时要注意使用它!(它可能会破坏Queue/Pipe中的数据)

请注意,multiprocessing.Event和multiprocessing.Semaphore的工作方式与threading.Event和threading.Semaphore完全相同。实际上,前者是后者的克隆。

如果您真的需要使用线程,则无法直接终止线程。但是,您可以使用“守护线程”。实际上,在Python中,线程可以标记为“守护进程”:

yourThread.daemon = True  # set the Thread as a "daemon thread"

主程序将在没有任何活动的非守护线程时退出。换句话说,当您的主线程(当然是一个非守护线程)完成其操作时,即使仍有一些守护线程在工作,程序也会退出。
请注意,在调用start()方法之前,必须将线程设置为daemon
当然,您可以并且应该在multiprocessing中使用daemon。在这里,当主进程退出时,它会尝试终止所有守护子进程。
最后,请注意,sys.exit()os.kill()不是选择。

为了澄清线程与多进程之间的区别,可以参考https://dev59.com/UGMl5IYBdhLWcg3wzpnV。 - serv-inc
1
我喜欢这个答案……它是关于线程本质的纯粹真相。 - repzero

11

如果你的线程正在执行 Python 代码,那么你面临的问题比无法杀死它更大。GIL 将防止任何其他线程甚至运行你将用于杀死线程的指令。 (经过一些研究,我了解到解释器会定期释放 GIL,所以前面的说法是错误的。但是下面的评论仍然成立。)

你的线程必须以合作的方式编写。也就是说,它必须定期检查一个信号对象(例如信号量),主线程可以使用该对象来指示工作线程自愿退出。

while not sema.acquire(False):
    # Do a small portion of work…
或:
for item in work:
    # Keep working…
        # Somewhere deep in the bowels…
        if sema.acquire(False):
            thread.exit()

1
如何获取那个 sema - Frozen Flame
1
https://docs.python.org/2/library/threading.html#semaphore-objects - Marcelo Cantos
2
我的线程正在等待 raw_input().... :S - ntg
1
@ntg 你需要进行非阻塞读取。在Unix系统中,你可以在标准输入和一个os.pipe()上使用select()函数。要终止等待的线程,只需关闭管道。这将唤醒线程,表示管道已准备就绪,线程可以在那一点上简单地退出。 - Marcelo Cantos

8

你无法从另一个线程杀死一个线程。你需要向另一个线程发出信号,告诉它应该结束。这里的“信号”不是指使用signal函数,而是指你必须安排一些线程之间的通信。


5
要点是,我想要结束的线程可能会在函数中忙碌,如果它变得过于繁忙(挂起、停滞),我希望能够突然终止它。 - pythonic
1
把线程设置成不会挂起或者陷入停滞状态岂不更好?通常你需要使用一些互斥锁/信号量/标志来通知线程并使其跳出循环。 - DipSwitch
1
为线程使用超时,并使用信号处理程序捕获该超时中断。 - bos
1
对计时器对象的引用可以让您设置一个时间,当计时器触发时,它会调用您设置的任何函数。在这种情况下,它可以终止线程。http://docs.python.org/release/2.4.2/lib/timer-objects.html - EEP

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接