简体   繁体   English

如何停止在python中运行无限循环的线程?

[英]How to stop threads running infinite loops in python?

I've made a program which has a main thread that spawns many other threads by subclassing the threading.Thread class. 我已经编写了一个程序,该程序具有一个主线程,通过子类化threading.Thread类可以生成许多其他线程。

Each such child thread runs an infinite while loop, and inside the loop I check a condition. 每个这样的子线程运行一个无限的while循环,然后在循环内检查条件。 If the condition is true, I make the thread sleep for 1 second using time.sleep(1) and if it's false, then the thread performs some computation. 如果条件为true,则使用time.sleep(1)使线程休眠1秒,如果条件为false,则线程将执行一些计算。

The program itself works fine and I've achieved what I wanted to do, my only remaining problem is that I seem unable to stop the threads after my work is done. 该程序本身运行良好,并且已经实现了我想做的事情,我唯一剩下的问题是工作完成后,我似乎无法停止线程。 I want the user to be able to kill all the threads by pressing a button or giving a keyboard interrupt like Ctrl+C. 我希望用户能够通过按按钮或给键盘中断(如Ctrl + C)杀死所有线程。

For this I had tried using the signal module and inserted a conditon in the threads' loops that breaks the loop when the main thread catches a signal but it didn't work for some reason. 为此,我尝试使用信号模块,并在线程的循环中插入一个条件,当主线程捕获到信号但由于某种原因而无法工作时,该条件会中断循环。 Can anyone please help with this? 谁能帮忙吗?

EDIT: This is some of the relevant code snippets: 编辑:这是一些相关的代码段:

def sighandler(signal,frame):
    BaseThreadClass.stop_flag = True
class BaseThreadClass(threading.Thread):
    stop_flag = False
    def __init__(self):
        threading.Thread.__init__(self)
    def run(self,*args):
        while True:
            if condition:
               time.sleep(1)
            else:
               #do computation and stuff
            if BaseThreadClass.stop_flag:
               #do cleanup
               break

Your basic method does work, but you've still not posted enough code to show the flaw. 您的基本方法确实有效,但是您仍然没有发布足够的代码来显示缺陷。 I added a few lines of code to make it runnable and produced a result like: 我添加了几行代码以使其可运行,并产生了如下结果:

$ python3 test.py
thread alive
main alive
thread alive
main alive
^CSignal caught
main alive
thread alive
main alive
main alive
main alive
^CSignal caught
^CSignal caught
main alive
^Z
[2]+  Stopped                 python3 test.py
$ kill %2

The problem demonstrated above involves the signal handler telling all the threads to exit, except the main thread, which still runs and still catches interrupts. 上面演示的问题涉及信号处理程序告诉所有线程退出, 主线程除外,该主线程仍在运行并仍捕获中断。 The full source of this variant of the sample snippet is: 该示例代码段的完整来源为:

import threading, signal, time

def sighandler(signal,frame):
    BaseThreadClass.stop_flag = True
    print("Signal caught")

class BaseThreadClass(threading.Thread):
    stop_flag = False
    def __init__(self):
        threading.Thread.__init__(self)
    def run(self,*args):
        while True:
            if True:
               time.sleep(1)
               print("thread alive")
            else:
               #do computation and stuff
               pass
            if BaseThreadClass.stop_flag:
               #do cleanup
               break

signal.signal(signal.SIGINT, sighandler)

t = BaseThreadClass()
t.start()

while True:
    time.sleep(1)
    print("main alive")

The problem here is that the main thread never checks for the quit condition. 这里的问题是主线程从不检查退出条件。 But as you never posted what the main thread does, nor how the signal handler is activated, or information regarding whether threads may go a long time without checking the quit condition... I still don't know what went wrong in your program. 但是,因为您从未发布过主线程的功能,信号处理程序的激活方式或有关线程是否可能在不检查退出条件的情况下运行很长时间的信息……我仍然不知道您的程序出了什么问题。 The signal example shown in the library documentation raises an exception in order to divert the main thread. 库文档中显示的信号示例引发了一个异常,以转移主线程。

Signals are a rather low level concept for this task, however. 但是,信号是此任务的一个较低级别的概念。 I took the liberty of writing a somewhat more naïve version of the main thread: 我自由地编写了主线程的一个稍微天真的版本:

try:
    t = BaseThreadClass()
    t.start()
    while True:
        time.sleep(1)
        print("main alive")
except KeyboardInterrupt:
    BaseThreadClass.stop_flag = True
    t.join()

This version catches the exception thrown by the default interrupt handler, signals the thread to stop, and waits for it to do so. 此版本捕获默认中断处理程序引发的异常,向线程发出信号以使其停止并等待它停止。 It might even be appropriate to change the except clause to a finally , since we could want to clean the threads up on other errors too. 甚至可以将except子句更改为finally ,因为我们也可能希望清除其他错误的线程。

If you want to do this kind of "cooperative" polled-shutdown, you can use a threading.Event to signal: 如果要进行这种“合作式”轮询关闭,则可以使用threading.Event发出信号:

import threading
import time

def proc1():
    while True:
        print("1") # payload
        time.sleep(1)

        # have we been signalled to stop?
        if not ev1.wait(0): break 

    # do any shutdown etc. here
    print ("T1 exiting")

ev1 = threading.Event()
ev1.set()

thread1 = threading.Thread(target=proc1)
thread1.start()

time.sleep(3)

# signal thread1 to stop
ev1.clear()

But be aware that if the "payload" does something blocking like network or file IO, that op will not be interrupted. 但是请注意,如果“有效负载”做了诸如网络或文件IO之类的阻塞操作,该操作将不会被中断。 You can do those blocking ops with a timeout, but that obviously will complicate your code. 您可以使用超时来阻止那些阻塞操作,但这显然会使您的代码复杂化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM