如何给守护线程一个停止事件

How to give a daemon thread a stop event

我正在努力了解 python 中的线程,我拼凑了一个简单的 tkinter UI 可以 运行 后台任务以更好地理解它是如何工作的.
我似乎已经到了可以创建一个单独的线程并与 GUI 交互的地步,但是当我第二次尝试执行任务时问题就来了。

我相信我缺少的是一种告诉守护进程何时停止线程的方法。
到目前为止,这是我的代码:

import threading
import tkinter as tk
from collections import deque
from threading import Thread
from random import randint
from time import sleep


class Emitter:
    def __init__(self):
        self.stop_event = threading.Event()
        self.thread = Thread(target=self.emit_text)
        self.running = False

    def emit_text(self):
        sleep(3)
        messageQueue.append(f'Random number: {randint(0, 100)}')
        # self.thread.set()

    def start_emit(self):
        ui.consume_text()
        self.thread.setDaemon(True)
        self.thread.start()


class UI:
    def __init__(self):
        self.root = tk.Tk()
        self.label = tk.Label(self.root, text='Original text')
        self.label.pack()
        start = tk.Button(self.root, text='Start Download', command=lambda x=Emitter(): x.start_emit())
        start.pack()

    def consume_text(self):
        try:
            self.label['text'] = messageQueue.popleft()
        except IndexError:
            self.root.after(ms=1000, func=self.consume_text)


messageQueue = deque()
ui = UI()
ui.root.mainloop()

我试图理解其他答案,但我无法理解你是如何告诉 daemon/thread 它停止的条件是什么。
该程序在您第一次单击按钮时按预期工作,但如果您再次尝试单击它,它会给出错误 RuntimeError: cannot set daemon status of active thread,即使我已经等待发射器完成它的任务

感谢@Solomon Slow 的评论,我遇到的问题是我试图重新启动线程,但实际上我应该每次都创建一个新线程。
为了解决这个问题,我更改了 class 发射器 class 以在每次调用 start_emit() 时创建一个新线程。

固定的class:

class Emitter:
    def __init__(self):
        self.stop_event = threading.Event()

    def emit_text(self):
        sleep(3)
        messageQueue.append(f'Random number: {randint(0, 100)}')

    def start_emit(self):
        ui.consume_text()
        thread = Thread(target=self.emit_text)
        thread.start()

我还删除了 self.thread.setDaemon(True) 行。