On Feb 13, 2008, at 3:41 AM, Siamak Sarmady wrote:
> Hello,
>
> In one of my programs I am just using the Display component of Mason.
>
> The problem is that when I close Display window, program continues to
> run in Background. What else should I do to terminate the entire
> program? (Is it the state object which remains in memory?)
This is a question with a very complex answer, and it's not easy to
answer given the hack that you're doing here. So some background.
When you press "play" on the Console, here's what it does in short:
1. Calls start() on the GUIState (which in turn calls start() on the
underlying SimState)
2. Spawns a thread (the "play thread") which:
2a. Blocks waiting for all Swing Events to have completed (using
SwingUtilities.invokeAndWait)
2b. Loops:
2b.i. calls simulation.step() to step the simulation once. This
automatically synchronizes on the schedule until the step is completed.
2b.ii. Blocks until all Swing Events have completed
When we try (from the Swing event thread) to repaint the window or
inspect an object in the window or modify a feature of an object, we
first synchronize on the underlying Schedule. This causes us to
block until the playThread's call of simulation.step() has completed,
so we don't modify or read bad stuff on the model.
When you call "stop" on the Console we:
1. Interrupt the play thread (since we were called via a java event
-- mouse click on stop button -- we know we have control and the
underlying thread is blocking waiting for our Swing Event to complete.
2. Kill the play thread
3. Call finish() on the GUIState
[Keep in mind that you should call init() on the GUIState and also
quit() on it when you first create it and later destroy it at the end
of your application.]
The important item to note here is that MASON's GUI facilities are
designed to hand off a baton and forth between an underlying thread
(called the "play thread") and Swing. Whoever has the baton is
allowed to read/write the model and the schedule, otherwise they have
to wait. Waiting for and acquiring the baton is easy: just
synchronize on the Schedule.
It looks like you are deviating from this model in two ways:
1. You're not handing off the baton. This could result in race
conditions you don't want to see.
2. Your model thread (the equivalent of the "play thread" above) is
the underlying main() thread perhaps? It's not made clear.
Ordinarily in Java GUI applications, the main thread just sets things
up and dies.
The easiest way to handle this is to NOT call start(), but rather let
the console handle it for you. Just call console.pressPlay() to
start the simulation, and console.pressStop() to stop the
simulation. You really ought to do these from the GUI thread, not
the main thread. If you're not in the GUI thread, you can still do
this by creating a small Runnable, whose sole function in life is to
call console.pressPlay(), and adding him to SwingUtilities with a
SwingUtilities.invokeAndWait(...). Likewise for console.pressStop().
When the Display2D's window is disposed, by default it calls
Display2D.quit() first. But note that in Java by default when you
click on a close box in a window, it doesn't dispose the window. It
just hides it. That's what MASON is relying on -- it's just hiding
the window. You can change the behavior of closing the window to
actually dispose the window (and thus call quit()), look at JFrame's
documentation. Basically, let Display2D create its window with
createFrame(), and then change that frame's close-box behavior.
If you do this, you will also want to hook into JFrame's quit()
method to quit your program when the window is closed. The quick and
dirty, ugly way to do this is to just override the quit() method in
Display2D to call System.exit(0). That will kill everything
immediately and quit your application. A better approach would be to
call console.doClose(), which will cleanly shut down and dispose
everything.
Good luck! Beware that multithreading coding in Swing is
nontrivial! :-)
Sean
|