Help with multithreading and state in a scientific simualtion program

M

mgorbach

Im writing a program that does monte carlo simulation and im having
trouble figuring out how to get the threading model right. I have a
simulation class which contains all simulation data and methods to run
the simulation for an x number of sweeps. An instance of this object is
declared in the class of my main form. The main form handles graphics
(it shows the particles moving on the form). I am now trying to split
up the work so that the UI thread is separate from the thread running
the simulation prgoram. I will also probably be adding a form to
allowing viewing of the same data by chart, so i need the simualtion
object to be accessible from multiple forms. The simulation object has
an event which is triggered when the simulation moves a particle, with
the form listening for that event and updating itself. The problem is
when i run the simulation in a separate thread i get exceptions when
trying to access graphics objects for drawing (because im accessing UI
elements from a nonUI thread).

Can someone help me out to figure out a good structure for the program?
 
D

Dave

To draw you'll have to invoke calls on the thread that created the form (or control your drawing to).

Control.InovkeRequired will let you know if the code is executing on a non-ui thread
Control.Invoke(new MethodInvoker(ParameterlessMethod)) will invoke a method on the ui-thread where you should place your drawing
code:

if (ctrl.InvokeRequired)
ctrl.Invoke(new MethodInvoker(DoDraw));
else
DoDraw();
 
M

Michael Gorbach

if figured that much out. the problem is my simulation object does not
have access to the form it is running in, so it cant use invoke. Also
.... im noticingf something strange and id like an explanation ... for
some reason if i run Invalidate() in the form while running on the
nonui thread, the form_paint executes in the ui thread by itself. how
does this happen and why?
 
D

Dave

WinForms controls use the message loop. The paint message is sent to itself when you invoke Invalidate(). The message is received
on the ui thread, and the rest is history.

I suggest adding a parameter to your simulation object's constructor:

public Simulator(Form owner)
{
this.owner = owner;
}

If you need multiple forms to access the object, a Singleton pattern might be what your after:

public class Simulator
{
// thread-safe singleton pattern implementation
public static readonly Simulator Instance = new Simulator();

// disallow construction of the object from external classes
private Simulator() {}

public void Run(Form owner)
{
// Todo: start a new thread and run the simulation on the specified form (owner)
}

[...]

Simulator.Instance.Run(this); // this, is a Form reference

You can expose events that your form classes can listen to on the instance.
 
M

Michael Gorbach

Thanks for the help Dave.
I think the singelton might just be what im looking for.
Heres more details on the way im trying to rewrite the program:
I have a main form which controls how many sweeps and tells the
simulation to run.
I have a graphics form which displays the molecules, instantiated as an
object inside the mainform.
I have a table form which displays the simulation as a table of
particles, also instantiated inside the mainform.
I need to have only one simulation in the entire program at once, and i
need both viewer forms to be able to access it, and the main form to be
able to tell it to run. I want the simulation running in a separate
thread from the GUI. The thing to note is that there will be no outside
changing to the simulation object after it is instantiated, its
members need only be "read" by the viewers.
I feel like there should be only global instance of simulation that all
three forms can access ... is singelton what i need?
 
D

Dave

Absolutely. The pattern is for classes that need to be instantiated, like other non-static classes, except with one different
criteria; The class must only be instantiated once.

By providing the "private" constructor you are ensuring that the class will not be instatiated (without the use of reflection) by
calling code except for the single "Instance" that is created automattically by the class itself.

In the example I gave you, it can be viewed that the Run method provides construction logic for the component. All other
properties/fields should probably be private, readonly or properties with only "get" accessors. This will ensure that calling code
may not modify any instance fields after the singleton is instantiated. (You can use the "Run" method, or whatever you'd like to
call it, to provide a means for state-settings.)

Applied, your "controller" form can call "Run" on the "Instance" with any state-setting parameter's you'd like to include. Your
"charting" form can listen to public instance events that you may declare or just access public read-only properties at runtime.
The same would go for your "tabular" form.

GL
 
M

Michael Gorbach

one more question ... my simulation triggers events that are listened
to by the charting form, but it seems that the methods wired to those
events (in the charting form) are executing in the simulation thread
and not in the forms gui thread. Why, and how do i fix this? I cant
have forms listening to events from the simulation object if in the
eventhandlers i cant manipualte the GUI ...
 
J

Jon Skeet [C# MVP]

Michael Gorbach said:
one more question ... my simulation triggers events that are listened
to by the charting form, but it seems that the methods wired to those
events (in the charting form) are executing in the simulation thread
and not in the forms gui thread. Why, and how do i fix this? I cant
have forms listening to events from the simulation object if in the
eventhandlers i cant manipualte the GUI ...

Event handling delegates are always executed on the thread that raises
the event. You need to call Control.Invoke/BeginInvoke within the event
handler to get back to the UI thread.
 
M

Michael Gorbach

right ... thats what iv understood from my reading. what i dont
understand is ... why does the invalidate event behave differently from
the cuustom event that i created? When i raise the invalidate event it
executes in the GUI thread, when i raise my event the handling method
is called in the simulation thread.
 
J

Jon Skeet [C# MVP]

Michael Gorbach said:
right ... thats what iv understood from my reading. what i dont
understand is ... why does the invalidate event behave differently from
the cuustom event that i created? When i raise the invalidate event it
executes in the GUI thread, when i raise my event the handling method
is called in the simulation thread.

Where and how are you raising the invalidate event? My guess is that
you're either raising it in the UI thread, or that the method you call
to raise it is *actually* calling Invoke/BeginInvoke to raise it in the
UI thread.
 
M

Michael Gorbach

my simulation fires an event when a move is accepted (the simulation is
changed). This event is caught by the charting form in a handler. If i
run invokerequired in the handler, it returns true. The handler runs
this.invalidate(); When i run invokerequired in the invalidate method,
it returns false. It is almost as if something is doing an implied
invoke.
 
J

Jon Skeet [C# MVP]

Michael Gorbach said:
my simulation fires an event when a move is accepted (the simulation is
changed). This event is caught by the charting form in a handler. If i
run invokerequired in the handler, it returns true. The handler runs
this.invalidate(); When i run invokerequired in the invalidate method,
it returns false. It is almost as if something is doing an implied
invoke.

Could you post a short but complete program which demonstrates this?

See http://www.pobox.com/~skeet/csharp/complete.html for details of
what I mean by that.
 
D

Dave

Mr Skeet,

In a previous post I mentioned that the Invalidate method is sending a windows message to the control/form that is being
invalidated. A paint message is then received by the WndProc procedure running on the UI Thread.

Isn't this correct?
 
J

Jon Skeet [C# MVP]

Dave said:
In a previous post I mentioned that the Invalidate method is sending
a windows message to the control/form that is being invalidated. A
paint message is then received by the WndProc procedure running on
the UI Thread.

Isn't this correct?

I'm not sure, but Invalidate shouldn't be called on a non-UI thread as
far as I know.
 

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

Top