"Robin Dunn" <robin@alldunn.com> writes:
> If I make a simplified threads demo and run the thread with a small enough
sleep
> time I get a crash in mscrtv.dll on app close. I presume this is because a
> control that has been destroyed is accessed through the thread.
>
> So...what are the safe bounds given a thread that may occasionally do
minimal
> processing?
1. Don't do any GUI function or method calls from the thread.
2. Construct and send events from the thread to the GUI objects with
wxPostEvent to interact between them. Alternativly, use something like
Pyhton's Queue object to send info from the thread to the GUI, and have the
GUI pull items form the queue in idle time. The thread can call
wxWakeUpIdle() to ensure that there will be an idle event soon.
3. Don't exit the MainLoop (close all frames) until all threads are
completed, or at least in a state where they won't send any more events.
Thats the tricky part, if the event generating thread has caused a que of events
then ensuring it doesn't send anymore isnt enough(?). Do I also have to
'Disconnect' the window from the event to be safe?
Or is it true that you wont get any more events after onclosewindow on the top
frame?
Occasionally I also get this error instead of the crash in mscrtv
Unhandled exception in thread:
Traceback (most recent call last):
File "testThreads.py", line 44, in Run
evt = UpdateBarEvent(self.barNum, int(self.val))
TypeError: object of type 'None' is not callable
Of course trying to print things out changes the timing but it appears
'UpdateBarEvent' has disappeared from the 'main' namespace.
Here's the script I'm using which is just the thread demo without bar graphs.
I've just realized I'm no longer getting the busyinfo box so onclosewindow is
no longer running but I can't see why.
If you have a chance could you take a quick look, thanks.
from wxPython.wx import *
import thread
import time
from whrandom import random
···
#----------------------------------------------------------------------
wxEVT_UPDATE_BARGRAPH = 25015
def EVT_UPDATE_BARGRAPH(win, func):
win.Connect(-1, -1, wxEVT_UPDATE_BARGRAPH, func)
class UpdateBarEvent(wxPyEvent):
def __init__(self, barNum, value):
wxPyEvent.__init__(self)
#print wxPyEvent, self.SetEventType
self.SetEventType(wxEVT_UPDATE_BARGRAPH)
self.barNum = barNum
self.value = value
#----------------------------------------------------------------------
class CalcBarThread:
def __init__(self, win, barNum, val):
self.win = win
self.barNum = barNum
self.val = val
def Start(self):
self.keepGoing = self.running = true
thread.start_new_thread(self.Run, ())
def Stop(self):
self.keepGoing = false
def IsRunning(self):
return self.running
def Run(self):
while self.keepGoing:
# print self.barNum,self.val,repr(UpdateBarEvent),self.win
evt = UpdateBarEvent(self.barNum, int(self.val))
wxPostEvent(self.win, evt)
del evt
time.sleep(0.05)
self.running = false
#----------------------------------------------------------------------
#----------------------------------------------------------------------
class TestFrame(wxFrame):
def __init__(self, parent):
wxFrame.__init__(self, parent, -1, "Thread Test", size=(450,300))
EVT_UPDATE_BARGRAPH(self, self.OnUpdate)
self.thread = CalcBarThread(self, 0, 50)
self.thread.Start()
EVT_CLOSE(self, self.OnCloseWindow)
def OnUpdate(self, evt):
pass #print 'updated'
def OnCloseWindow(self, evt):
busy = wxBusyInfo("One moment please, waiting for threads to die...")
self.thread.Stop()
running = 1
while running:
running = 0
running = self.thread.IsRunning()
time.sleep(0.1)
self.Destroy()
#---------------------------------------------------------------------------
class MyApp(wxApp):
def OnInit(self):
self.frame = wxFrame(NULL, -1, "Test", wxPoint(0, 0), wxSize(600, 800))
sizer = wxBoxSizer(wxVERTICAL)
win = TestFrame(self.frame)
sizer.Add(win,1,wxEXPAND)
self.frame.SetAutoLayout(true)
self.frame.SetSizer(sizer)
sizer.Fit(self.frame)
sizer.SetSizeHints(self.frame)
self.SetTopWindow(self.frame)
self.frame.Show(true)
return true
#----------------------------------------------------------------------
app = MyApp(0)
app.MainLoop()
--
wxPython