290 likes | 297 Views
Learn about asynchronous interruptible programming in Java, including the Interruptible interface and handling AsynchronouslyInterruptedExceptions. Explore examples and best practices for implementing interruptible methods.
E N D
Introduction Concurrent Programming Communication and Synchronization Completing the Java Model Overview of the RTSJ Memory Management Clocks and Time Scheduling and Schedulable Objects Asynchronous Events and Handlers Real-Time Threads Asynchronous Transfer of Control Application requirements Basic model Continue Resource Control Schedulability Analysis Conclusions Roadmap
Asynchronous Transfer of Control Lecture aims • To explain the high level model and how to use the Interruptible interface • To consider multiple AsynchronouslyInterruptedExceptions (AIE) • To introduce the Timed class and show an example
ATC Summary • All methods that are prepared to allow the delivery of an asynchronous exception must place the AIE exception in their throw list • The RTSJ calls such methods AI-methods (Asynchronously Interruptible) • If a method does not do this, it is called ATC-deferred and the asynchronous exception is not delivered but held pending until the thread is in a method which has the appropriate throw clause • Synchronized statement and methods are ATC deferred.
AIE public class AsynchronouslyInterruptedException extends java.lang.InterruptedException { ... public synchronized void disable(); public boolean doInterruptible (Interruptible logic); public synchronized boolean enable(); public synchronized boolean fire(); public boolean clear (); public staticAsynchronouslyInterruptedException getGeneric(); // returns the AsynchronouslyInterruptedException which // is generated when RealtimeThread.interrupt() is invoked // … }
Interruptible • An object which wishes to provide an interruptible method does so by implementing the Interruptible interface • The run method is the method that is interruptible; the interruptedAction method is called by the system if the run method is interrupted public interface Interruptible{ public void interruptAction ( AsynchronouslyInterruptedException exception); public void run ( AsynchronouslyInterruptedException exception) throws AsynchronouslyInterruptedException; }
Interruptible • Once this interface is implemented, the implementation can be passed as a parameter to the doInterruptible method in the AIE class • The method can then be interrupted by calling the fire method in the AIE class • Further control over the AIE is given by • disable • enable • isEnabled Only one schedulable object can be executing a doInterruptible at once
Warning Note, the firing of an AsynchronouslyInterrupted-Exception has no effect if there is no currently active doInterruptible. The firing is NOT persistent. Hence, care must be taken as there may be a race condition between one thread calling a doInterruptible and another thread calling fire on the same AIE. To help cope with this race condition, fire will return false, if there is no currently active doInterruptible or the AIE is disabled.
Mode Change Example I import javax.realtime.*; public class ModeA implements Interruptible { public void run(AsynchronouslyInterruptedException aie) throws AsynchronouslyInterruptedException { // operation performed in Mode A } public void interruptAction( AsynchronouslyInterruptedException aie){ // reset any internal state, so that when Mode A // becomes current, it can contine } } // similary for ModeB
Mode Change Example II import javax.realtime.*; public class ModeChanger extendsAsynchronouslyInterruptedException { public static final int MODE_A = 0; public static final int MODE_B = 1; public ModeChanger(int initial) { super(); if(initial == MODE_A) current = MODE_A; else if(initial == MODE_B) current = MODE_B; else throw new IllegalArgumentException(); } public synchronized int currentMode(){ return current; }
Mode Change Example III public synchronized void setMode(int nextMode){ if(nextMode == MODE_A | nextMode == MODE_B) current = nextMode; else throw new IllegalArgumentException(); } public synchronized void toggleMode(){ if(current == MODE_A) current = MODE_B; else current = MODE_A; } private int current; }
Mode Change Example IV ModeChanger modeChange = newModeChanger( ModeChanger.MODE_A) ; public void run() // inside a RT thread with // PeriodicParameters { ModeA modeA = new ModeA(); ModeB modeB = new ModeB(); boolean ok = true; boolean result; while(ok) { if(modeChange.currentMode() == ModeChanger.MODE_A) result = modeChange.doInterruptible(modeA); //throw away result else result = modeChange.doInterruptible(modeB); //throw away result ok = waitForNextPeriod(); } } signaller: modeChange.toggleMode(); modeChange.fire();
A Persistent AIE I import javax.realtime.*; public class PersistentAIE extends AsynchronouslyInterruptedException { // first attempt public PersistentAIE(){ super(); outstandingAIE = false; } public boolean fire() { if(!super.fire()) { outstandingAIE = true; return false; } else return true; }
A Persistent AIE II public boolean doInterruptible(Interruptible logic) { if(outstandingAIE){ outstandingAIE = false; logic.interruptAction(this); return true; } else { return super.doInterruptible(logic); } } private volatile boolean outstandingAIE; } Why does this fail?
A Persistent AIE III public boolean doInterruptible(Interruptible logic) { if(outstandingAIE){ outstandingAIE = false; logic.interruptAction(this); return true; } else { // fire comes in here!! return super.doInterruptible(logic); } }
A Persistent AIE IV import javax.realtime.*; public class PersistentAIE extends AsynchronouslyInterruptedException implements Interruptible { public PersistentAIE() {/* As before */ } public boolean fire() { /* As before */ }
A Persistent AIE V public boolean doInterruptible(Interruptible logic) { this.logic = logic; return super.doInterruptible(this); } public void run(AIE aie) throws AIE { if(outstandingAIE) { outstandingAIE = false; super.fire(); } else { logic.run(aie); } } public void interruptAction(AIE aie) {logic.interruptAction(aie); } private volatile boolean outstandingAIE; private Interruptible logic; }
Non InterruptibleMethod Non InterruptibleMethod AIE3.doInterruptible(A) AIE2.doInterruptible(B) AIE1.doInterruptible(C) Non Interruptible Method Call Interruptible A Interruptible C Interruptible B Multiple AIEs and Nested ATCs Pending AIE: AIE3 Pending AIE: AIE2 Pending AIE: none AIE2.fire() AIE3.fire() AIE1.fire() Discarded
Nested ATCs • Once the ATC-deferred region is exited, the currently pending AIE is thrown • This AIE will be caught by the interruptAction of the inner most nested AIE first • However, it will typically propagate the ATC
Nested ATC Eg public class NestedATC { AIE AIE1 = new AIE(); // similarly for AIE2 and AIE 3 public void method1() { /* ATC-deferred region */} public void method2() throws AIE { AIE1.doInterruptible(new Interruptible() { public void run(AIE e) throws AIE {method1(); }
Nested ATC Eg Continued public void interruptAction( AIE e) { // recovery here } }); } // similarly for method3, whose run method calls method2, // and for method4, whose run method calls method3
The Timed Class I • With Real-Time Java, there is a subclass of AsynchronouslyInterruptedException called Timed • Both absolute and Relative times can be used public class Timed extends AsynchronouslyInterruptedException implements java.io.Serializable { public Timed(HighResolutionTime time) throws IllegalArgumentException; public boolean doInterruptible (Interruptible logic); public void resetTime(HighResolutionTime time); }
The Timed Class II • When an instance of the Timed class is created, a timer is created and associated with the time value passed as a parameter • A timer value in the past results in the AIE being fired immediately the doInterruptible is called. • When a time value is passed which is not in the past, the timer is started when the doInterruptible is called • The timer can be reset for the next call to doInterruptible by use of the resetTime method
Imprecise Computation I • The algorithm consists of a mandatory part which computes an adequate, but imprecise, result • An optional part then iteratively refines the results • The optional part can be executed as part of a doInterruptible attached to a Timed object • The run method updates the result from within a synchronized statement so that it is not interrupted
Imprecise Computation II • First, the ImpreciseResult is defined. Here, the result is an integer and there is a boolean indicating whether the result is imprecise public class ImpreciseResult { public int value; // the result public boolean preciseResult; // indicates if value is imprecise }
Imprecise Computation III import javax.realtime.*; public class ImpreciseComputation { public ImpreciseComputation(HighResolutionTime T) { CompletionTime = T; //can be absolute or relative result = new ImpreciseResult(); } private int compulsoryPart() {/* function which computes the compulsory part */}; public ImpreciseResult service() // public service { result.preciseResult = false; result.value = compulsoryPart(); // compute the compulsory part Interruptible I = new Interruptible() {
Imprecise Computation IV public void run( AsynchronouslyInterruptedException exception) throws AsynchronouslyInterruptedException { // this is the optional function which improves // on the compulsory part’s value boolean canBeImproved = true; while(canBeImproved) { // improve result synchronized(result) { /* write result */ } } result.preciseResult = true; } public void interruptAction( AsynchronouslyInterruptedException exception) {result.preciseResult = false;} };
Imprecise Computation V Timed t = new Timed(CompletionTime); boolean res = t.doInterruptible(I)); // execute the optional part, // throw away the result of doInterruptible return result; } private HighResolutionTime CompletionTime; private ImpreciseResult result; }
Summary • The RTSJ combines thread interruption with exception handling and introduces the notion of an asynchronously interrupted exception (AIE) • The presence of a throws AsynchronouslyInterru-ptedException in a method’s signature indicates that the method is prepared to allow asynchronous transfers of control • The high-level approach involves creating objects which implement the Interruptible interface • Note, the firing of an AsynchronouslyInterrupted-Exception has no effect if there is no currently active doInterruptible • The firing is NOT persistent