Thank you very much for your time and kind help. The design of Mason
seems very good to me (for the purpose it has designed). I think I
should be able to handle this with your descriptions.
Thank you again,
> 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
> 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
> Good luck! Beware that multithreading coding in Swing is
> nontrivial! :-)