使用tk在多线程Python控制台应用程序中模糊,可重复的崩溃

Tom*_*rly 4 python tkinter

在我的多线程(*)控制台应用程序中使用tk导致它在没有stacktrace的情况下崩溃,给出消息"Tcl_WaitForEvent:Notifier not initialized Abort trap".

症状是我的所有程序的功能都运行良好,直到我提起tk窗口 - 然后下一次操作将导致崩溃.

立即搜索发现Tkinter对于Python线程是不安全的,所以我确保除了我的主线程之外我没有调用任何Tk函数.崩溃继续.

我失去了几个小时,因为我相信这是我使用的特定命令使程序崩溃 - 但最终我意识到任何键盘输入都会使程序崩溃.

经过大量的调试后,我最终将其归结为一个演示该问题的小程序,揭示了我认为是一个错误或者肯定是需要Tkinter库中的文档的功能.

我正在调试这个帖子.我将它张贴和回答我的问题,因为它会阻止下一个人从它浪费了一天的希望.

-

(* - 是的,它肯定需要多线程.我有一个用于我的套接字连接的线程,一个侦听麦克风并找到级别的线程,一个驱动我的串口的线程等等.在每种情况下,都是我正在阅读线程,大部分时间自然会阻塞.)

Tom*_*rly 7

解决方案!

问题是如果你从tk线程的不同线程中读取Python的raw_input,tk会崩溃!

一个小程序演示该问题是在这里.如果你运行它,它会从第二个线程中非常愉快地获得键盘输入 - 直到你输出一个空的tk窗口时输入命令"tk".您可以使用该窗口执行任何操作 - 直到您在整个程序崩溃时键入控制台窗口并按回车键.

为什么我在一个不是主线程的线程中读取raw_input?

我的程序是一个控制台应用程序,但我控制了很多不同的部分,其中一个是pi3d OpenGL ES 2.0图形库,必须以主帧Python线程的帧速率或接近帧速率进行更新.

如何解决它?

"简单"足够 - 注册tk菜单事件,直接获取密钥!除了这是一个糟糕的解决方案,因为你必须模仿控制台为你做的所有事情 - 删除,左右箭头等等.但那是我必须要做的.

程序应该成为一个完全成熟的tk应用程序吗?

但是我不能这样做 - 这个程序的重点在于你可以通过一个终端窗口来运行它 - 经常闯入无头机器.坦率地说,我更有可能成为一个诅咒计划!

tk窗口是整个事物的一小部分 - 如果您没有连接硬件(或者不想让自己在脸上闪烁),那么在开发时只显示模拟灯光的窗口.我不会尝试在无头机器上提起它,这没关系.

这是一个错误吗?

我总是厌恶将这样的标签贴在不属于我自己的软件上,但我很难想出任何其他描述.它会导致崩溃,并且崩溃不会产生任何类型的有用信息.我认为Tkinter在从不同的线程调用时简单地崩溃有些蹩脚,但至少记录了这种行为(如果你深入了解一下) - 在这种情况下,我正在调用内置的Python,所以我没有期望它完全与这个库交互的基础,并且没有这个问题的文档.

可以有一个解决方法吗?

我有点希望有一个解决方法 - 这个单页程序是一长串功能上的单个项目已经变成了一整天令人头疼的调试会话而且我不想要至少在此之后再扔一天,而这一次都没有实际产生新功能.

最好的事情是,如果tk团队承认这是一个错误并提出了修复.但是从现在开始一年之后,我不希望在我的桌面上...

所以也许真正最好的事情就是如果有某种方法让tk简单地忽略键盘,而不是崩溃.我做了一个小实验,TK的"忙",但没有工作,似乎并不为事情的正确排序.

过了一会儿,我现在正考虑将照明作为一个独立的程序运行,使用Python的Subprocess库进行单独的子进程,并通过stdin发送文本命令.如果这是唯一正在解决的问题,那实际上就是过度杀伤

得到它了.

用sys.stdin.readline()替换raw_input()可以解决问题 - 至少在演示中(我更新了).随意下载并自己试验吧!

我希望这能节省别人的时间.

  • 很好的调试.但我的解决方案只是添加一个`matplotlibrc`文件,其中包含一行代码,它将`backend:agg`写入python项目的根目录. (3认同)

Tom*_*iak 3

就我而言(正如 @Tom Swirly 的答案下的评论中提到的),解决方案是切换到非交互式后端:

import matplotlib
matplotlib.use('Agg')
Run Code Online (Sandbox Code Playgroud)