【发布时间】:2022-01-22 12:42:13
【问题描述】:
我有以下问题:我想用 tkinter 创建一个 GUI,它对从套接字发送的信号作出反应。例如,我希望能够在收到 end 信号时终止应用程序。
为此,我有一个函数,在一个单独的线程中运行,它监听信号并采取相应的行动。但是,当我尝试销毁 tkinter-GUI 时,程序会停止,并给出以下错误消息:
致命的 Python 错误:PyEval_RestoreThread:函数必须在持有 GIL 的情况下调用,但 GIL 已释放(当前 Python 线程状态为 NULL) Python 运行时状态:已初始化
我重新创建了这个最小的工作示例,给出了相同的行为:
import tkinter as tk
import time
import threading
class Gui(tk.Frame):
"""Minimal GUI with only a button"""
def __init__(self, master: tk.Tk):
tk.Frame.__init__(self, master)
self.pack()
tk.Button(self, text='Spam').pack()
class Client:
"""Client for handling signals"""
def __init__(self, master: tk.Tk):
self.master = master
self.gui = Gui(self.master)
self.signal = None # Initialize signal
self.thread = threading.Thread(target=self.listen_thread)
self.running = True
self.thread.start()
def listen_thread(self):
"""Listen for signals and handle actions"""
while self.running:
signal = self.signal # Dummy signal, set by external method, instead of received message from socket
if signal == 'end': # End signal received
self.master.destroy() # Destroy tkinter GUI, error occurs here
self.running = False # Terminate while loop
else:
time.sleep(0.2)
def send_signal_after(receiver: Client, delay: float = 2.0):
"""Send a signal to the client after short delay"""
time.sleep(delay)
receiver.signal = 'end'
if __name__ == '__main__':
root = tk.Tk()
client = Client(root)
threading.Thread(target=send_signal_after, args=(client,)).start()
root.mainloop()
if client.thread: # Check if thread is still running, if so, wait for termination
client.thread.join()
我在 MacOS 12.1、Python 3.10 上运行它。
还有其他方法可以终止应用程序吗?我知道,我可能可以使用 sys.exit(),但我想以一种更简洁的方式来执行此操作。
谢谢!
【问题讨论】:
标签: python multithreading tkinter