我有一个Tkinter应用程序,有时会在Windows下崩溃。该错误是一个通用的'程序已停止工作,需要关闭'。
检查事件日志后,我发现tcl85.dll
是导致崩溃的库。
我的猜测是我的程序中有一个错误,它会滥用tcl api并导致tcl进入未定义状态,最终导致崩溃,或者tcl85本身存在错误。
我的问题是,如何诊断出这个问题的原因?哪些工具可以帮助获得类似程序错误的回溯?我已经检查了Windows事件日志中的错误,但是那里的信息似乎不足以确定原因。
以下是事件日志错误的xml:
Name="Application Error"></Provider>
<EventID Qualifiers="0">1000</EventID>
<Level>2</Level>
<Task>100</Task>
<Keywords>0x0080000000000000</Keywords>
<TimeCreated SystemTime="2014-08-27 08:54:13"></TimeCreated>
<EventRecordID>6173</EventRecordID>
<Channel>Application</Channel>
<Computer>my.windows.8.tablet.computer</Computer>
<Security UserID=""></Security>
</System>
<EventData><Data><string>my_tkinter_app.exe</string>
<string>0.0.0.0</string>
<string>514e2c2f</string>
<string>tcl85.dll</string>
<string>8.5.2.15</string>
<string>53b1e888</string>
<string>c0000005</string>
<string>0007697f</string>
<string>1378</string>
<string>01cfc1d44828ecb0</string>
<string>C:\Users\ADMINI~1\DOWNLO~1\my_tkinter_app.exe</string>
<string>C:\Users\ADMINI~1\AppData\Local\Temp\_MEI35042\tcl85.dll</string>
<string>b7745a30-2dc7-11e4-9732-88124e8c7600</string>
<string></string>
<string></string>
</Data>
<Binary></Binary>
</EventData>
</Event>
从c0000005
我收集到存在访问冲突,但这仍然过于通用,无法确定原因。
不幸的是,我无法在Linux下重现崩溃,因此我正在寻找一种特定于Windows的方法来跟踪此问题。
答案 0 :(得分:1)
如果你有一个涉及Tcl的PDB文件(例如,因为你是自己构建的),最简单的方法就是在进程崩溃时简单地指示windows安全地使用MiniDump。
Windows错误报告(WER)系统具有执行此操作所需的部分,您只需设置一些注册表项并找到生成的.dmp文件。
查看所需内容http://msdn.microsoft.com/en-us/library/windows/desktop/bb787181%28v=vs.85%29.aspx:
一旦你有了崩溃转储,你只需用你选择的调试器(Visual Studio或Windbg)打开它并开始调试,将它指向你的PDB文件和微软符号服务器,并获得一个很好的崩溃堆栈跟踪。 / p>
答案 1 :(得分:1)
我在安装了Python 2.7.9的Windows 7桌面上出现了相同的错误,这在我的程序中是一个线程安全的问题。我不确定您的问题是否可以通过我的解决方案解决,只需分享即可。
对于在其他(主要)线程中运行tkinter的所有人,tkinter NOT THREAD SAFE 。在我的程序中,我必须在主线程中运行twisted reactor,所以我在另一个线程中运行tkinter UI。由于我在主线程中直接调用tkinter方法(如Text.insert()
),因此偶尔会因c0000005错误而崩溃。
阅读this bug report后,我用:
修改了基于tkinter的UI模块添加了after()
和queue.get_nowait()
的处理程序方法,如下所示:
def commandQueueHandler(self):
try:
while 1:
your_command = self.textCommandQueue.get_nowait()
if your_command is not None:
# execute the command ....
self.Text.update_idletasks()
except Queue.Empty:
pass
self.Text.after(100, self.commandQueueHandler)
此方法每100ms自触发一次以处理队列中的命令,但您必须触发 一次 才能使其正常工作。 (在初始化所有小部件之后,我在__init__
中触发此内容。)
在主线程中,我所要做的只是将命令/消息放入命令队列并等待它被处理。当然,在命令执行之前会有一点延迟。
那就是它!通过这个修改,我的程序在2周的压力测试后没有运行tcl c0000005错误。希望这会有所帮助。
P.S。请注意,只有窗口小部件类提供after()
方法,check this page for details。
答案 2 :(得分:0)
关于Tkinter不是线程安全的这个建议是现货。 就我而言,我以下列方式解决了问题:
self.root.after(10, self.monitor) #sets up the queue monitor
self.root.update_idletasks() # adding this call resolved the issue for me