在我的多线程(*)控制台应用程序中使用tk导致它在没有堆栈跟踪的情况下崩溃,给出消息“Tcl_WaitForEvent:Notifier not initialized Abort trap”。
症状是我所有程序的功能都运行良好,直到我调出tk窗口 - 然后下一次操作才会导致崩溃。
立即搜索发现Tkinter对于Python线程是不安全的,所以我确保除了主线程之外我没有调用任何Tk函数。崩溃继续。
我失去了几个小时,因为我相信这是我正在使用的特定命令使程序崩溃 - 但最终我意识到任何键盘输入都会使程序崩溃。
经过大量调试后,我最终将其归结为一个演示该问题的小程序,揭示了我认为是一个错误或者肯定是需要Tkinter库中的文档的功能。
我正在处理这个我正在调试的帖子。我将发布它并回答我自己的问题,希望它可以防止下一个人浪费一天的时间。
-
(* - 是的,它肯定需要多线程。我有一个用于我的套接字连接的线程,一个侦听麦克风并找到级别的线程,一个驱动我的串口的线程等等。在每种情况下,我在线上阅读的东西自然会在大部分时间内阻止。)
答案 0 :(得分:6)
解决方案!
问题是,如果你从与tk线程不同的线程中读取Python的raw_input,tk会崩溃!
展示此问题的小程序是here。如果你运行它,它会从第二个线程中非常愉快地获得键盘输入 - 直到你输出一个空的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()起了作用 - 至少在演示中(我更新了)。随意下载并自己试验吧!
我希望这能节省别人的时间。
答案 1 :(得分:1)
就我而言(如@Tom Swirly的回答下的评论所述),解决方案是切换到非交互式后端:
import matplotlib
matplotlib.use('Agg')