Nick said:
<snip>
Here's a more real-life like program done in both single threaded mode
and multi-threaded mode. You'll need PythonCard to try this. Just to
make the point, you will notice that the core code is identical between
the two (method on_menuFileStart_exe). The only difference is in the
setup code. I wanted to dismiss the myth that multi-threaded programs
are inherently *evil*, or that it's diffcult to code, or that it's
unsafe.....(what ever dirty water people wish to throw at it).
Don't ask me to try this in process!
To have fun, first run it in single threaded mode (change the main
program to invoke the MyBackground class, instead of the
MyBackgroundThreaded class):
Change:
app = model.Application(MyBackgroundThreaded)
to:
app = model.Application(MyBackground)
Start the process by selecting File->Start, and then try to stop the
program by clicking File->Stop. Note the performance of the program.
Now, run it in multi-threaded mode. Click File->Start several times
(up to 4) and then try to stop the program by clicking File->Stop.
If you want to show off, add several more StaticText items in the
resource file, add them to the textAreas list in MyBackgroundThreaded
class and let it rip!
BTW: This ap also demonstrates the weakness in Python thread - the
threads don't get preempted equally (not even close).
Two files follows (test.py and test.rsrc.py):
#!/usr/bin/python
"""
__version__ = "$Revision: 1.1 $"
__date__ = "$Date: 2004/10/24 19:21:46 $"
"""
import wx
import threading
import thread
import time
from PythonCard import model
class MyBackground(model.Background):
def on_initialize(self, event):
# if you have any initialization
# including sizer setup, do it here
self.running(False)
self.textAreas=(self.components.TextArea1,)
return
def on_menuFileStart_select(self, event):
on_menuFileStart_exe(self.textAreas[0])
return
def on_menuFileStart_exe(self, textArea):
textArea.visible=True
self.running(True)
for i in range(10000000):
textArea.text = "Got up to %d" % i
## print i
for j in range(i):
k = 0
time.sleep(0)
if not self.running(): break
try:
wx.SafeYield(self)
except:
pass
if not self.running(): break
textArea.text = "Finished at %d" % i
return
def on_menuFileStop_select(self, event):
self.running(False)
def on_Stop_mouseClick(self, event):
self.on_menuFileStop_select(event)
return
def running(self, flag=None):
if flag!=None:
self.runningFlag=flag
return self.runningFlag
class MyBackgroundThreaded(MyBackground):
def on_initialize(self, event):
# if you have any initialization
# including sizer setup, do it here
self.myLock=thread.allocate_lock()
self.myThreadCount = 0
self.running(False)
self.textAreas=[self.components.TextArea1, self.components.TextArea2,
self.components.TextArea3, self.components.TextArea4]
return
def on_menuFileStart_select(self, event):
res=MyBackgroundWorker(self).start()
def on_menuFileStop_select(self, event):
self.running(False)
self.menuBar.setEnabled("menuFileStart", True)
def on_Stop_mouseClick(self, event):
self.on_menuFileStop_select(event)
def running(self, flag=None):
self.myLock.acquire()
if flag!=None:
self.runningFlag=flag
flag=self.runningFlag
self.myLock.release()
return flag
class MyBackgroundWorker(threading.Thread):
def __init__(self, parent):
threading.Thread.__init__(self)
self.parent=parent
self.parent.myLock.acquire()
threadCount=self.parent.myThreadCount
self.parent.myLock.release()
self.textArea=self.parent.textAreas[threadCount]
def run(self):
self.parent.myLock.acquire()
self.parent.myThreadCount += 1
if self.parent.myThreadCount==len(self.parent.textAreas):
self.parent.menuBar.setEnabled("menuFileStart", False)
self.parent.myLock.release()
self.parent.on_menuFileStart_exe(self.textArea)
self.parent.myLock.acquire()
self.parent.myThreadCount -= 1
if self.parent.myThreadCount==0:
self.parent.menuBar.setEnabled("menuFileStart", True)
self.parent.myLock.release()
return
if __name__ == '__main__':
app = model.Application(MyBackgroundThreaded)
app.MainLoop()
Here's the associated resource file:
{'application':{'type':'Application',
'name':'Template',
'backgrounds': [
{'type':'Background',
'name':'bgTemplate',
'title':'Standard Template with File->Exit menu',
'size'

400, 300),
'style':['resizeable'],
'menubar': {'type':'MenuBar',
'menus': [
{'type':'Menu',
'name':'menuFile',
'label':'&File',
'items': [
{'type':'MenuItem',
'name':'menuFileStart',
'label':u'&Start',
},
{'type':'MenuItem',
'name':'menuFileStop',
'label':u'Sto&p',
},
{'type':'MenuItem',
'name':'menuFile--',
'label':u'--',
},
{'type':'MenuItem',
'name':'menuFileExit',
'label':'E&xit',
'command':'exit',
},
]
},
]
},
'components': [
{'type':'StaticText',
'name':'TextArea1',
'position'

10, 100),
'text':u'This is a test',
'visible':False,
},
{'type':'StaticText',
'name':'TextArea2',
'position'

160, 100),
'text':u'This is a test',
'visible':False,
},
{'type':'StaticText',
'name':'TextArea3',
'position'

10, 150),
'text':u'This is a test',
'visible':False,
},
{'type':'StaticText',
'name':'TextArea4',
'position'

160, 150),
'text':u'This is a test',
'visible':False,
},
] # end components
} # end background
] # end backgrounds
} }