[wxPython] Qs on Threads demo &&|| background processing

Hi, can any wxpython thread guru's help me with this?

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? and what happens if the event fires whilst the previous one is being
processed - are they aggregated or just stacked up?

Alternatively are there other methods people use for background processing.

Cheers

···

--
wxPython

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.

and what happens if the event fires whilst the previous one is being
processed - are they aggregated or just stacked up?

Stacked up.

···

--
Robin Dunn
Software Craftsman
robin@AllDunn.com Java give you jitters?
http://wxPython.org Relax with wxPython!

"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