首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在使用事件系统时,如何正确地杀死/退出/停止线程?

在使用事件系统时,如何正确地杀死/退出/停止线程?
EN

Stack Overflow用户
提问于 2021-02-22 14:01:43
回答 1查看 40关注 0票数 0

我正在用python创建一个gui工具。这里出现了一个问题,当我通过点击button.The来触发子线程来运行一些逻辑代码时,在process.And过程中可能会发生一些错误,处理时间可能很长,如果发生错误,我会发送一个错误事件来通知EventManager,并调用一些函数来终止/退出该子线程,因为继续运行左边的逻辑代码是没有意义的。但是我不知道如何使用错误event.Could正确地杀死/退出/停止子线程,谁来帮帮我?

代码语言:javascript
复制
from queue import Queue, Empty
from threading import *
from tkinter import *
import time
from tkinter import ttk

EVENT_TYPE_1 = "Count"
EVENT_TYPE_2 = "Error"
MAX_NUMBER = 10
CUR_NUMBER = 0


class event_manager:
    def __init__(self):
        self._eventQueue = Queue()
        self._thread = Thread(target=self.Run, daemon=True)
        self._handlers = {}
        self._active = False

    def Start(self):
        self._active = True
        self._thread.start()

    def Run(self):
        while self._active is True:
            try:
                event = self._eventQueue.get(block=True, timeout=1)
                self.Process(event)
            except Empty:
                pass

    def Process(self, event):
        if event.type in self._handlers:
            for handler in self._handlers[event.type]:
                handler()
        else:
            pass

    def Stop(self):
        self._active = False
        self._thread.join()

    def addEventListenter(self, type_, handler):
        try:
            handlerList = self._handlers[type_]

        except KeyError:
            handlerList = []
            self._handlers[type_] = handlerList

        if handler not in handlerList:
            handlerList.append(handler)

    def removeEventListenter(self, type_, handler):
        try:
            handlerList = self._handlers[type_]
            if handler in handlerList:
                handlerList.remove(handler)
            if not handlerList:
                del self._handlers[type_]
        except KeyError:
            pass

    def sendEvent(self, event):
        self._eventQueue.put(event)


class Event:
    def __init__(self, event_event_name, cur_done_task, type_=None):
        self.type = type_
        self._event_name = event_event_name
        self._curDoneTask = cur_done_task


class EventSource:
    def __init__(self, event_name, event_mgr, max_number, type):
        self._event_name = event_name
        self._event_manager = event_mgr
        self._type = type
        self._max_number = max_number

    def count(self):
        global CUR_NUMBER
        for i in range(self._max_number):
            CUR_NUMBER = i + 1

            if CUR_NUMBER == 4:  # assume this is a error check function,if error occurs,it will send a error event,and hopefully this event can terminate the sub-thread which is exactly running current code 
                print("************ detect error occurred , this thread should be terminated immediately !")
                errorEvent = Event("error", CUR_NUMBER, type_=EVENT_TYPE_2)
                self._event_manager.sendEvent(errorEvent)

            print(
                "************ main thread start:now start process {} - count : {}".format(self._event_name, CUR_NUMBER))
            event = Event("test", CUR_NUMBER, type_=self._type)
            self._event_manager.sendEvent(event)
            time.sleep(1)


class GUIListener(Tk):
    def __init__(self):
        super(GUIListener, self).__init__()

        self.title("Progress GUI")
        self.geometry("1200x805+600+100")
        self.config(bg="#535353")
        self.resizable(True, True)
        self.taskThread = None

        self.progressBar = ttk.Progressbar(master=self, orient=HORIZONTAL, maximum=MAX_NUMBER, length=300)
        self.progressBar.pack()
        self.button = ttk.Button(self, text="Run", command=lambda: self.button_function(MAX_NUMBER))
        self.button.pack()

    def update_progress_value(self):
        print("************Sub thread start: detect progress bar value is now...{}".format(self.progressBar['value']))
        self.progressBar['value'] = CUR_NUMBER
        self.progressBar.update_idletasks()
        print("************Sub thread start: update progress bar value to...{}".format(CUR_NUMBER))

    def button_function(self, max_number):
        # though I can make some error check function before task thread starts,but I really want to discuss the way that using event-system here 
        es = EventSource("eventSource", eventMgr, max_number, EVENT_TYPE_1)
        self.taskThread = Thread(target=es.count, daemon=True).start()  # here to start the sub-thread which need to be terminated by error event

    def terminate_error_thread(self):  # this method will be called when GUIListener recieved error event and terminate the sub-thread immediately
        pass
        # TODO: but how to implement this method?


if __name__ == '__main__':
    gui = GUIListener()

    eventMgr = event_manager()
    eventMgr.addEventListenter(EVENT_TYPE_1, gui.update_progress_value)
    eventMgr.addEventListenter(EVENT_TYPE_2, gui.terminate_error_thread)

    eventMgr.Start()

    gui.mainloop()

希望控制台能给我提供如下日志:

代码语言:javascript
复制
************ main thread start:now start process eventSource - count : 1
************Sub thread start: detect progress bar value is now...0.0
************Sub thread start: update progress bar value to...1
************ main thread start:now start process eventSource - count : 2
************Sub thread start: detect progress bar value is now...1
************Sub thread start: update progress bar value to...2
************ main thread start:now start process eventSource - count : 3
************Sub thread start: detect progress bar value is now...2
************Sub thread start: update progress bar value to...3
************ detect error occurred , this thread should be terminated immediately !
EN

回答 1

Stack Overflow用户

发布于 2021-02-23 02:10:33

count函数中,当您想要退出时,您可以简单地中断循环。如果函数运行完毕,线程将自动退出。

例如,

代码语言:javascript
复制
class EventSource:
    def __init__(self, event_name, event_mgr, max_number, type):
        self._event_name = event_name
        self._event_manager = event_mgr
        self._type = type
        self._max_number = max_number

    def count(self):
        global CUR_NUMBER
        for i in range(self._max_number):
            CUR_NUMBER = i + 1

            if CUR_NUMBER == 4:  # assume this is a error check function,if error occurs,it will send a error event,and hopefully this event can terminate the sub-thread which is exactly running current code 
                print("************ detect error occurred , this thread should be terminated immediately !")
                errorEvent = Event("error", CUR_NUMBER, type_=EVENT_TYPE_2)
                # self._event_manager.sendEvent(errorEvent)
                break

            print("************ main thread start:now start process {} - count : {}".format(self._event_name, CUR_NUMBER))
            event = Event("test", CUR_NUMBER, type_=self._type)
            self._event_manager.sendEvent(event)
            time.sleep(1)
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66310719

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档