Crashing Python.exe with TkInter

B

Bryan Olson

I've run into a problem with Python/TkInter crashing, with an
attempt to read illegal addresses, on Win on Win2000 and WinXP.

With some web-searching, I found that people say not to
manipulate TkInter from multiple threads, except that the call
event_generate() is safe. I assume the call adds an event to
Tk's queue, and later the thread running mainloop will() pick up
the event.

I tried to write a general-purpose thread-runner. In the code
below, 'thread-it' runs a given function in a new thread, saves
the result, and triggers event_generate(). When the mainloop
handles the event, it calls a second given function with the
saved result.

The code below *seems* to work. It requires only the current
Python distribution. To make it usually crash, un-comment the
'print' statement in add_to_listbox(). That's all.

With no prints, it works. Adding prints in various places
causes it usually to crash with an unreadable-memory error from
the OS. I get the same behavior on the command-line and in
Idle. Occasionally, it prints something like:

TclExecuteByteCode: abnormal return at pc 45: stack top 39 < entry
stack top 59
TclExecuteByteCode execution failure: end stack top < start stack top

which is usually also accompanied by the read addressing error.

I'm sure I've previously been able to print from multiple Python
threads. Can anyone tell what is going on?



from Tkinter import *
import thread
import time

class Application(Frame):

def __init__(self):
Frame.__init__(self, None)
self.event_name_cntr = 0
self.pack()
self.listbox = Listbox(self)
self.listbox.pack(side=TOP)

def add_to_listbox(self, msg):
self.listbox.insert(END, msg)
# print "Adding", msg

def thread_it(self, finish_func, asyc_func, args=()):
""" Create a thread that calls asyc_func(*args), then trigger
an even with event_generate(). When the event loop handles
the event, call finish_func with the return value of asyc_func.
"""
event_name = "<<j7A5x0VjqZ3b_%x>>" % self.event_name_cntr
self.event_name_cntr += 1
result = [None]
def _on_finish(_):
self.unbind(event_name)
finish_func(result[0])
def do():
result[0] = asyc_func(*args)
self.event_generate(event_name)
self.bind(event_name, _on_finish)
thread.start_new_thread(do, ())

app = Application()

def fin(s):
""" When the async function returns, we'll add its output
to the list box.
"""
app.add_to_listbox(s)

def async(n):
""" In the threads, we'll just sleep then return a string.
"""
time.sleep(2.0)
return "Got %d asyncronously." % n

for i in range(5):
# Run a few threads
app.thread_it(fin, async, )

app.mainloop()



Thanks,
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,233
Members
46,821
Latest member
AleidaSchi

Latest Threads

Top