Design Question: GUI+Threads.

  • Thread starter Frithiof Andreas Jensen
  • Start date
F

Frithiof Andreas Jensen

Hi All,

I am tinkering with a stock-market analysis program that needs to have (at
least one) a worker thread for processing real-time data and a GUI where one
can control/monitor the function of the worker, set parameters and so forth.

Is there an elegant and generic way to implement the typical "Model, View,
Controller" pattern so that the "Model+Controller" execute in the context of
the worker thread and the "View" will execute in the GUI thread - and
communication between the two is thread-safe and simple?
 
S

Syver Enstad

Frithiof Andreas Jensen said:
Hi All,

I am tinkering with a stock-market analysis program that needs to have (at
least one) a worker thread for processing real-time data and a GUI where one
can control/monitor the function of the worker, set parameters and so forth.

Is there an elegant and generic way to implement the typical "Model, View,
Controller" pattern so that the "Model+Controller" execute in the context of
the worker thread and the "View" will execute in the GUI thread - and
communication between the two is thread-safe and simple?

One way to do it:

Use two Queue.Queue's. Do non blocking get's and put's from the gui on
a timer. Do blocking gets from the queue instance that the GUI calls
put on, do blocking put's on the queue that the GUI calls get from.

I usually wrap the use of Queue behind a method interface, so that the
GUI calls methods on the threaded class to get and put. If you want to
to use a thread pool you can easily make all the threads can share the
queue instances.
 
B

Brian Kelley

You might make your life easier by having the controller and the view be
on the main thread and dispatch a new model to the work thread.

Contoller -> starts or attaches to view
-> starts a new model

model -> signals events to controller which updates view
controller -> sets model states when necessary.

Usually you can wrap model events into gui events and let the gui's
mainloop sort them out and dispatch them to the controllers callbacks.

In python it is thread safe to set variables across the thread boundary,
the model will have to check for these variables changing though. The
standard variable is set by thread.kill() see the threading module for
more details.

What gui framework are you using?

Brian Kelley
 
F

Frithiof Andreas Jensen

Thaks for the reply,

Brian Kelley said:
Syver Enstad wrote:
You might make your life easier by having the controller and the view be
on the main thread and dispatch a new model to the work thread.

Hmm. I think that makes sense, since it is the GUI that "demands"
attention - I was doing sort-of the other way round by having a thread
dispatching messages to models AND the GUI thread....
Usually you can wrap model events into gui events and let the gui's
mainloop sort them out and dispatch them to the controllers callbacks.

So, To make sure that I understand correctly:

I will have one Controller per Worker; the Controller interacts with the GUI
and it is the Controller that "understands" that the Worker is running in a
separate thread and maps GUI/Worker events across the thread boundary by
some means -

I was planning to use of a Dispatcher/Mailbox System:

The worker thread(S) blocks on an input queue until a message is in that
queue - then the worker thread process the message and places a result in an
output queue. The results in the output queue(s) of each worker are read by
the main thread and placed in the input queues of other workers or in the
GUI.....most of the time a worker will sleep, waiting for work.

The input and output queues would be owned by the workers, the "distribution
lists" i.e. which event goes where would be owned by a "Dispatcher" running
in the main thread .

While this is fine for Data, setting parameters etc. is clumsy: One needs to
setup a filter to sort parameter messages from the data and do special
processing - i would rather keep only data in the message loop.
In python it is thread safe to set variables across the thread boundary,
the model will have to check for these variables changing though.

....I will need locking in the models setXyz() methods so that I do not stomp
on some data that the worker thread is using?
What gui framework are you using?

wxPython - in the hope that SciPy eventually will do a Python 2.2.3 release,
so that by the time I need it, I can get my hands on all those neat
Plotting, Numeric and Stats tools waiting to be liberated ;-)
 
B

Brian Kelley

Frithiof said:
Thaks for the reply,




Hmm. I think that makes sense, since it is the GUI that "demands"
attention - I was doing sort-of the other way round by having a thread
dispatching messages to models AND the GUI thread....

<snip>
I was planning to use of a Dispatcher/Mailbox System:

The worker thread(S) blocks on an input queue until a message is in that
queue - then the worker thread process the message and places a result in an
output queue. The results in the output queue(s) of each worker are read by
the main thread and placed in the input queues of other workers or in the
GUI.....most of the time a worker will sleep, waiting for work.

This seems very doable. You have at least two options: 1) use a wxTimer
to periodically tell the controller to check the worker's output queues
or 2) have the worker send a new wxEvent to the view with the result
data. This could be as simple as:

wxEVT_WORKER_RESULT = wxNewEventType()

def EVT_WORKER_RESULT(win, func):
win.Connect(-1, -1, wxEVT_WORKER_RESULT, func)

class WorkerResultEvent(wxPyEvent):
def __init__(self, result):
wxPyEvent.__init__(self)
self.SetEventType(wxEVT_WORKER_RESULT)
self.data = data

# event wrapper so that the worker thread can send
# results
class EventWrapper:
def __init__(self, window):
self.window = window
def setResult(self, data):
wxPostEvent(self.win, WorkerResultEvent(data))

class WorkerThread(thread):
def __init__(self, eventSender):
...
def Run(self): ...
...
self.eventSender(result)
self.blockForNextJob()

class View:
def __init__(self, controller,...):
EVT_WORKER_RESULT(self, self.OnResult)
def OnResult(self, evt):
self.controller.OnResult(evt.result)

A good example of this is in the wxPython thread example. Their view is
their controller though.
 

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

No members online now.

Forum statistics

Threads
474,169
Messages
2,570,919
Members
47,458
Latest member
Chris#

Latest Threads

Top