【问题标题】:Accessing the main thread in a TKinter script?访问 TKinter 脚本中的主线程?
【发布时间】:2013-12-04 22:41:29
【问题描述】:

我想明白为什么我会收到以下错误TclStackFree: incorrect freePtr. Call out of sequence?,但我不知道如何解决这个问题。

我的脚本摘要

我的PythonTKinter 脚本由三个活动线程组成。主线程和两个子线程。其中一个子线程负责侦听 UDP 消息,另一个负责绘制接收到的数据(使用 Matplotlib)。据我所知,问题是我试图从两者访问 gui同时子线程。例如,我可能正在接收 UDP 消息并尝试在 gui 上显示它们,同时尝试绘制以前接收到的数据的图形。这并不少见,因为我接收 UDP 数据包的速率(高达每秒 10,000 个)。

代码

两个子线程使用 -

thread.start_new_thread(self.function, ())

UDP 监听线程

def Listen(self):
    if self.udpClient.IsConnected():
        while True:
            #Listen for messages
            data = self.udpClient.listen(1024)
            #Add the data to the gui
            self.AddNewData(data)
            if self.disconnectFlag:
                break

def AddNewData(self, data):
    self.listbox.insert(END, data)
    receivedData.append(data)

图形线程

def UpdateGraph(self):
    while True:
        if readyToGraph:
            self.plot.clear()
            self.plot.hexbin(data[0], data[1], bins = "log", extent = self.extent)
            self.canvas.draw()

EDIT: 
if __name__ == "__main__":
    root = TK()
    gui = MainWindow(root, "Receiver")
    root.mainloop()

就像我说的那样,我认为问题在于有时侦听器线程尝试将数据添加到列表框,同时图形线程尝试更新图形。

我试过了...

在尝试修改 GUI 之前使用 root.after_idle(...) 但这只会锁定主线程。示例:self.listbox.insert(END, data) -> root.after_idle(self.listbox.insert, END, data)(我在 self.plot.clear()self.plot.hexbin(...)self.canvas.draq() 之前也调用了 root.after_idle

我还按照建议查看了threading.conditionqueue.queue here,但我找不到太多关于这两个的信息。 (所以我还没有真正尝试过任何一种解决方案)

问题

如何从子线程访问 gui 而不锁定它或导致上述错误?

【问题讨论】:

  • 90% 确定你必须在主线程上进行绘图。
  • @tcaswell 打电话给root.after_idle? (root 我的意思是TK,对不起,我是想在问题中说明这一点)
  • 另外,如果您正在嵌入,请不要导入pyplot(我不知道您是否是)。也不要使用 plot 作为名称,它技术上不会与 plot() 冲突,但它会使您的代码非常难以阅读。
  • 我对 tk 和线程没有太多经验,但是使用 QT 你不能从工作线程调用任何绘图函数。我假设 TK 有某种回调或计时器来告诉主线程在准备好时查看来自读取器线程的数据
  • 如果我不担心将数据添加到列表框中,只需绘制数据图表,那么一切正常。所以这让我觉得我可以在不进入主线程的情况下绘制图表..

标签: python multithreading matplotlib tkinter


【解决方案1】:

这里是 tkinter-discuss 邮件列表中讨论内容的链接: https://mail.python.org/pipermail/tkinter-discuss/2013-November/thread.html

这是本质:

嗨,

afaik after() / after_idle() 调用不是线程安全的!

根据我对 Andreas 提供的代码的研究,我发现 event_generate() 方法是调用 tk 的唯一线程安全方法 线程而不让它轮询某些东西。 (正如 Guido 和 在其他页面上看到的其他人似乎都在投票......为什么?)

brgds,

-- 一月

【讨论】:

  • 所以我不确定如何实现这一点。你知道如何使用 event_generate 吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-27
  • 1970-01-01
  • 2012-11-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多