如何使用按键输入安全地停止 Python 个线程

How to safely stop Python threads with key input

在我的应用程序中,我有两个线程。主要的和“线程”。 therad 生成一些数据并将其存储在 python 列表中。主线程周期性地复制“线程”生成的列表的内容。两个线程都有一个无限循环。我的目标是在我按下任意键+输入时停止两个线程。为实现此目标,程序必须在线程 运行ning 时等待键盘输入。我以为我需要另一个线程(可以说是管理器),它只在执行期间等待键盘输入。这是我首先尝试的:

class managerThread(threading.Thread):
    is_running = True
    def __init__(self):
        threading.Thread.__init__(self)
        signal.signal(signal.SIGINT, self.kill_all)
        signal.signal(signal.SIGTERM, self.kill_all)
      
    def run(self):
        input("Press any key+enter to stop: ")
        self.is_running = False
    
    def kill_all(self,signum, frame):
        print("Process ended with keyboard interrupt")
        self.is_running = False
        sys.exit(-1)

        
class thread(threading.Thread):
    mgr = managerThread()
    mgr.start()
    def __init__(self):
        threading.Thread.__init__(self)
    
    def run(self):
        while (self.mgr.is_running):
            print("this is acquiring data")
            sleep(2.5)
            
        self.mgr.join()
        print("manager stopped")


if __name__ == "__main__":
    thread = thread()
    thread.start()
    while (thread.mgr.is_running):
        print("this is copying data")
        sleep(3)
        
    thread.join()
    print("thread is stopped")
    sys.exit(0)

上面的代码正是我想做的。但这似乎不正确。管理器管理所有其他的,但它是在一个从属线程中创建的。另一个问题是人们可能会尝试在不同的线程中创建多个管理器。这是必须严格避免的事情。然后我想manager一定是被managedclasses继承的。这是我尝试过的:

class managerThread(threading.Thread):
    is_running = True
    def __init__(self):
        threading.Thread.__init__(self)
        signal.signal(signal.SIGINT, self.kill_all)
        signal.signal(signal.SIGTERM, self.kill_all)
        self.start()
      
    def run(self):
        input("Press any key+enter to stop: ")
        self.is_running = False
    
    def kill_all(self,signum, frame):
        print("Process ended with keyboard interrupt")
        self.is_running = False
        sys.exit(-1)

        
class thread(managerThread):
    def __init__(self):
        super().__init__()
        threading.Thread.__init__(self)
    
    def run(self):
        while (self.is_running):
            print("this is acquiring data")
            sleep(2.5)
            
        print("manager stopped")


if __name__ == "__main__":
    thread = thread()
    thread.start()
    while (thread.is_running):
        print("this is copying data")
        sleep(3)
        
    thread.join()
    print("thread is stopped")
    sys.exit(0)

如第二个代码所示,主要部分是相同的。我试图将 thread 作为 managerThread 的 child。但是,这是行不通的。经理从不执行“运行”方法。所以我无法停止其他线程。另一个关键问题是我不知道如何用 join() 停止 super()。我确定我在 class 继承方面犯了一个错误,但我无法解决问题,因为我没有太多的 OOP 经验,线程使我的困惑加倍。
注意:我不关心线程的同步。
我的问题是:
- 创建管理器线程是否正确以安全地停止从属线程?如果不是,正确的方法是什么?
- 为什么第二个代码不起作用?我必须修改什么才能让它工作?
- 为什么 parent class 正在初始化但它永远不会 运行ning "运行" 方法?
- 我相信 parent class 永远不会开始,但是如果它真的开始了,我怎么能在第二个代码中停止它呢?
谢谢。

即使我不想使用全局变量来安全地停止所有线程,我也找不到没有全局 运行 标志的解决方案。我还尝试将一个可变变量传递给管理器线程,但我没有成功。这是一个工作草图,解释了我如何解决我的问题。我希望这可以帮助别人。同时,如果有人提出更好的解决方案,我会很高兴 :)。
注意:我没有调试

import sys
import threading, queue
import signal
from time import sleep
import numpy as np

global_running = False

class managerThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        signal.signal(signal.SIGINT, self.kill_all)
        signal.signal(signal.SIGTERM, self.kill_all)
      
    def run(self):
        global is_running
        is_running = True
        input("Press any key+enter to stop: ")
        is_running = False
        print("manager finished")
    
    def kill_all(self,signum, frame):
        global is_running
        is_running = False
        print("Process ended with keyboard interrupt")
        sys.exit(-1)

        
class thread(threading.Thread):   
    __mgr = managerThread() 
    __mgr.start()
    running = True
    def __init__(self):
        threading.Thread.__init__(self)
        self.myvar = 0
        self.queue = queue.Queue()
    
    def currentVar(self):
        var = np.empty(1)
        while (var.size<=1):
            var = self.queue.get()
        self.queue.task_done()
        return var
    
    def run(self):
        global is_running
        while (is_running):
            print("this is acquiring data")
            sleep(2.5)
            self.myvar = np.empty(5)
            self.queue.put(self.myvar)
        
        self.running = False
        self.__mgr.join()
        print("manager stopped")


if __name__ == "__main__":
    thread = thread()
    thread.start()
    while (thread.running):
        # var = thread.queue.get()
        var = thread.currentVar()
        print ("value is: ", var)
        # thread.queue.task_done()
     
    thread.join()
    print("thread is stopped")
    sys.exit(0)