|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Objectsim.engine.AsynchronousSteppable
Fires up a separate thread which runs until the simulation model requests it be halted. This mechanism makes possible parallel threads which run in the background independently of the schedule being stepped. Note that the use of such threads makes the simulation unable to guarantee replicability.
Like all multithreaded stuff, AsynchronousSteppables are inherently dangerous and not to be trifled with: they access data at the same time as other threads, and so must deal with locking. In general if you lock on the Schedule, you are guaranteed atomic access to the underlying simulation model. You'll need to do this for even basic things such as accessing the random number generator. Locking on the Schedule is fairly course-grained, however: the simulation model obtains a lock on the Schedule for the whole duration of a Schedule's step. Instead you might create your own lock shared between the AsynchronousSteppable and the main thread which allows access to some piece of data you both need in a more fine-grained fashion. In this case, make certain that the GUI isn't trying to read that data (to display it, say), or that the GUI obtains a lock when it needs to as well. If you have no idea what we're talking about: don't use an AsynchronousSteppable.
When an AsynchronousSteppable is stepped, it fires off a thread which performs the asynchronous task. This task could be an infinite loop (or otherwise very long process) or it could be a short one-shot thing which runs and ends. Infinite loops can be paused and resumed (for checkpointing) and they can be stopped entirely.
AsynchronousSteppables automatically register themselves to be stopped at the end of the simulation (and when stopped, they unregister themselves). But if the task is an infinite loop, it's possible you may wish to stop the loop before the simulation ends, perhaps at an agreed-upon point in the schedule. The easiest way to do this is to get a stopper() and schedule it on the schedule, along these lines:
AsynchronousSteppable s = ... Steppable stopper = s.stopper(); schedule.scheduleOnce(s....); schedule.scheduleOnce(stopper....);
If the task is a SHORT, one-shot process and the user can reasonably wait for the task to complete after he has presed the 'stop' button, then run(false) should perform the asynchronous task, run(true) should be set to do nothing, and halt(true) and halt(false) should both do nothing. Here's some code to show how to form such a beast.
AsynchronousSteppable s = new AsynchronousSteppable() { protected void run(boolean resuming) { if (!resuming) { // do your stuff here } } protected void halt(boolean pausing) { } // nothing };
If the task is an infinite loop or otherwise long process, it needs to be pausable, resumable, and haltable. In this case, run(false) should perform the asynchronous task, halt(false) and halt(true) should both cause the thread to die or trigger events which will soon lead to thread death halt(...) returns, and run(true) should fire up the task loop again after it had been halted with halt(true). The most common situation is where you don't distinguish between your thread being killed temporarily or being killed permanently. Here's some code for this situation:
AsynchronousSteppable s = new AsynchronousSteppable() { boolean shouldQuit = false; double[] shouldQuitLock = new double[1]; // an array is a unique, serializable object boolean shouldQuit() { synchronized(shouldQuitLock) { return shouldQuit; } } protected void run(boolean resuming) { while(!shouldQuit()) { // do your stuff here -- assuming it doesn't block... } // we're quitting -- do cleanup here if you need to // now reset our flag shouldQuit = false; } protected void halt(boolean pausing) { synchronized(shouldQuitLock) { shouldQuit = val; } } };
Let's say the task needs to distinguish between being paused and being quit. In this case you need a custom way of handling pausing and knowing that you're resuming (perhaps to save state away). Here's some code for this situation:
AsynchronousSteppable s = new AsynchronousSteppable() { boolean shouldQuit = false; double[] shouldQuitLock = new boolean[1]; // an array is a unique, serializable object boolean shouldPause = false; double[] shouldPauseLock = new boolean[1]; // an array is a unique, serializable object boolean shouldQuit() { synchronized(shouldQuitLock) { return shouldQuit; } } boolean shouldPause() { synchronized(shouldPauseLock) { return shouldPause; } } protected void run(boolean resuming) { if (resuming) { // we're resuming from a pause -- re-set up here if you have to } else // (!resuming) { // we're starting fresh -- set up here if you have to } while(!shouldQuit() && !shouldPause()) { // do your stuff here -- assuming it doesn't block... } if (shouldPause()) { // we're pausing -- do cleanup here if you need to } else // if (shouldQuit()) { // we're quitting -- do cleanup here if you need to } // now reset our flags shouldPause = false; shouldQuit = false; } protected void halt(boolean pausing) { if (pausing) synchronized(shouldPauseLock) { shouldPause = val; } else synchronized(shouldQuitLock) { shouldQuit = val; } } };
Field Summary | |
protected SimState |
state
|
Constructor Summary | |
AsynchronousSteppable()
|
Method Summary | |
protected void |
finalize()
|
protected abstract void |
halt(boolean pausing)
This method should cause the loop created in run(...) to die. |
void |
pause()
Requests that the AsynchronousSteppable shut down its thread (temporarily) and blocks until this occurs. |
void |
resume()
Fires up the AsynchronousSteppable after a pause(). |
protected abstract void |
run(boolean resuming)
This method should enter the parallel thread's loop. |
void |
step(SimState state)
Fires up the AsynchronousSteppable and registers it with the SimState. |
void |
stop()
Requests that the AsynchronousSteppable shut down its thread, and blocks until this occurs. |
Steppable |
stopper()
Call this method to get a Steppable, which when called, executes top() on the AsynchornousSteppable. |
Methods inherited from class java.lang.Object |
clone, equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Field Detail |
protected SimState state
Constructor Detail |
public AsynchronousSteppable()
Method Detail |
protected abstract void run(boolean resuming)
protected abstract void halt(boolean pausing)
public final void step(SimState state)
step
in interface Steppable
public final void stop()
stop
in interface Stoppable
public final void pause()
pause
in interface Asynchronous
public final void resume()
resume
in interface Asynchronous
protected void finalize() throws java.lang.Throwable
java.lang.Throwable
public final Steppable stopper()
|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |