首页 > 解决方案 > 如何使用键输入安全地停止 Python 线程

问题描述

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

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)

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

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。但是,这是行不通的。管理器从不执行“运行”方法。所以我不能停止其他线程。另一个关键问题是我不怎么停下super()join()。我确信我在类继承方面犯了一个错误,但我无法解决这个问题,因为我没有太多的 OOP 经验,而且线程使我的困惑加倍。
注意:我不关心线程的同步。
我的问题是:
- 创建管理器线程是否正确以安全地停止从属线程?如果没有,正确的方法是什么?
- 为什么第二个代码不起作用?我必须修改什么才能让它工作?
- 为什么父类正在初始化但它从不运行“运行”方法?
- 我相信父类永远不会开始,但如果它真的开始了,我怎么能在第二个代码中停止它?
谢谢你。

标签: pythonmultithreadingpython-multithreading

解决方案


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

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)

推荐阅读