Lecture 20:

Timed systems
Next
Timed systems
  • Untimed systems

    • Correctness (usually) depends on the order the actions are performed, and not on performing an action by a certain time

    • Independence from processor speed and thread scheduling

  • Timed systems

    • Correctness depends on performing the actions by a specific time

    • Dependence on processor speed and on scheduling strategies

    • Example: process that detects double clicks of the mouse.
      Assume two consecutive clicks take place at times t1 and t2:

      • t2 - t1 < t => double click : do a certain action

      • t2 - t1 >= t => do nothing
Previous Next
Programming timed systems
In this lecture we will see how to model and implement timed systems in Java. Simplifying assumption: The time for execution of program instructions can be ignored (i.e. assumed to be 0) wrt the time between external events

For instance, in the example of the double click above, the time for recognizing clicks and performing aritmetical operations is considered 0 w.r.t. the time between two consecutive clicks.

For many applications, this hypothesis is reasonable in practice: the operations in the processor are several order of magnitude faster than external events

The system that require specifying and guarranteeing an upper boud to execution time fall into a specialized area of concurrency called real-time systems.

Previous Next
Modeling timed systems
We will consider only the simplest model of timed systems, which is based on a notion of time
  • Global:
    • All processes share the same clock

  • Discrete:
    • The passage of time is signaled by successive ticks of the clock (clock cycle). The length of (real) time of the clock cycle is a constant of the system.

    • An event happens during two consecutive ticks, but we cannot detect exactly when (timing uncertainty)

    • We can increase the accuracy by having more ticks per second (i.e. by decreasing the length of the clock cycle), but we will always have some uncertainty

    • Example: the event e1 and the event e2 (say, two consecutive clicks of the mouse) happen during cycle 1 and cycle 3 respectively. We don't know exactly when. But we know that their distance is no more than 3 cycles and no less than 1.
                   e1            e2
         |------|------|------|------|------|------>  time 
         0      1      2      3      4      5        (clock ticks)
      
Previous Next
Implementation of timed systems
Two main approaches are possible:

  • Thread-based

    • the active entities of the system are threads.

    • use methods like sleep() and timed wait() to synchronize with time

  • Event-based

    • the active entities are objects which respond to timing events.

    • there is a time manager process which broadcast the tick action to all the program entities that need to be aware of the passage of time
Previous Next
The event-based approach
In this lecture will consider the event-based approach. Its advantages and disadvantages w.r.t. the thread-based approach are:

  • Advantages

    • When the number of active entities is very large, and the activity of each entity at every clock cycle is minimal, this approach is convenient because it avoids the overhead due to thread management and to mechanisms to ensure mutual esclusion

  • Disadvantages

    • Threads are simpler to design. They abstract from the details of how activities should be scheduled and interact. Especially for more complex kinds of interactions, the event-based approach becomes rapidly too complicated

    • The event-based scheme requires each timed object to examine its state at every clock cycle to see whether an event has occurred. If timed objects do not perform actions at every clock cycle the thread-based approach may be more efficient (threads are waken up only when there is work for them to do)
Previous Next
The event-based approach
  • Timed objects
       public interface Timed {
          void pretick();
          void tick();
       }
    

    • The pretick() method checks the state of the object and performs all the actions that are enabled in its current state

    • The tick() method updates the state and record the passage of time.

  • Time manager

    • Every timed object is registered with the time-manager, which implements a two-phase event broadcast.

    • During Phase 1, the pretick() method of each timed object is invoked

    • During Phase 2, the tick() method of each timed object is invoked.

    • Note that the two-phase model is essential to ensure that communication between timed objects is completed within a single clock cycle.
Previous Next
The time manager
public class TimeManager extends Thread
  implements AdjustmentListener{
  volatile int delay; // length of clock cycle
  ImmutableList clocked = null;

  public TimeManager(int d) {delay = d;}

  public void addTimed(Timed el) {
    clocked = ImmutableList.add(clocked,el);
  }

  public void removeTimed(Timed el) {
    clocked = ImmutableList.remove(clocked,el);
  }

  public void adjustmentValueChanged(AdjustmentEvent e) {
    delay = e.getValue();
  }

  public void run () {
    try {
      while(true) {
        try {
          Enumeration e = ImmutableList.elements(clocked);
          while (e.hasMoreElements()) //pretick broadcast
            ((Timed)e.nextElement()).pretick();
          e = ImmutableList.elements(clocked);
          while (e.hasMoreElements()) //tick broadcast
            ((Timed)e.nextElement()).tick();
        } catch (TimeStop s) {
            System.out.println("*** TimeStop");
            return;
        }
        Thread.sleep(delay);
      }
    } catch (InterruptedException e){}
  }
}
Previous Next
Example: a parcel-router device
The problem

  • A router can be seen as a binary tree. The arcs are called "chutes". The leaves are called "bins"

  • Parcels are dropped into the top of the router and fall by gravity through the various chutes.

  • Each intermediate node is associated to a switch. The position of the switch determines the chute in which the parcel is routed (left or right)

  • Each parcel has a code which represents its destination (the bin towards which it should be directed)

  • Above each switch there is a sensor that is able to read the code of a parcel, and set the switch accordingly
Parcel router demo
Previous Next
Timed objects in the parcel-router device
/**
*------------CHUTE-----------------
*/

class Chute implements ParcelMover,Timed {
    protected int i,T,direction;

    protected Parcel current = null;
    ParcelMover next = null;

    Chute(int len, int dir) {
        T = len;
        direction = dir;
    }

    // package enters chute
    public void enter(Parcel p) throws TimeStop {
        if (current!=null) throw new TimeStop();
        current = p; i = 0;
    }

    public void pretick() throws TimeStop {
        if (current==null) return;
        if (i == T) {
           next.enter(current); // package leaves chute
           current = null;
        }
    }

    public void tick(){
        if (current==null) return;
        ++i;
        current.move(direction);
    }

}

/**
*----------------Switch -------------------
*/

class Switch extends Chute implements SwitchControl {
    ParcelMover left  = null;
    ParcelMover right = null;
    private ParcelCanvas display;
    private int gate;

    Switch(int len, int dir, int g, ParcelCanvas d )
         { super(len,dir); display = d; gate = g;}

    public void setSwitch(int direction) {
        if (current==null) {  // nothing passing through switch
            display.setGate(gate,direction);
            if (direction==0)
               next = left;
            else
               next = right;
        }
    }

}

/**
*----------------DestinationBin -------------------
*/

class DestinationBin implements ParcelMover, Timed {

    private Parcel current;
    private boolean flash = false;
    private boolean off = false;
    private int tickCount = 0;
    private int destination;
    static int FLASHPERIOD = 10;

    DestinationBin(int destination)
      {this.destination = destination;}

    public void enter(Parcel p) throws TimeStop {
      if (current!=null) current.remove();
      current = p;
      flash = !(p.destination == destination);
    }

    public void pretick(){};

    public void tick() {
       tickCount = (tickCount+1)%FLASHPERIOD;
       if (tickCount==0 && flash) {
          off = !off;
          current.hide(off);
       }
    }
}
In this system, the sensors are not timed objects, essentially because they are "very thin": a parcel enters and exit a sensor within one clock cycle


/**
*----------------SensorController-------------------
*/

class SensorController implements ParcelMover {
  ParcelMover  next;
  SwitchControl controlled;
  protected int level;

  SensorController(int level){this.level=level;}

  // package enters and leaves within one clock cycle
  public void enter(Parcel p) throws TimeStop {
    route(p.destination);
    next.enter(p);
  }

  protected void route(int destination) {
    int dir = (destination>>level) & 1;
    controlled.setSwitch(dir);
  }
}

Previous Next
Example: Space invaders
Space invaders demo

  • Video games involve many activities, called sprites

  • In the example, sprites are the spaceship, the aliens, the missiles, and the explosions. They are all timed objects

  • At every clock cycle, every sprite is active. This is an example where the event-based approach is definitely more efficient than the thread-based approach. Also, it is much simpler to synchronize the screen updates with the sprite activity: we simply repaint the screen once per clock cycle

Some of the timed classes

    class Alien extends Sprite {
        int dir;

        Alien(int x) {
            super(alien,x,0,SpaceInvaders.theDisplay,SpaceInvaders.theTicker);
            setIncrement(1+(int)(Math.random()*10.0));
            int choice  = (int) (Math.random()*10.0);
            if (choice<3) dir = SOUTHWEST;
            else if (choice<7) dir = SOUTH;
            else dir = SOUTHEAST;
        }

        public void hit() {
            new Explosion(this);
            SpaceInvaders.score.alienHit();
            SpaceInvaders.detector.removeAlien(this);
            remove();
        }

        public void tick() {
            move(dir);
            if ((posY()>=AREA.height-height-1)||(posX()>=AREA.width-width-1)){
               SpaceInvaders.detector.removeAlien(this);
               remove();
            }
        }
    }

class CollisionDetector implements Timed {
    ImmutableList aliens = null;
    ImmutableList missiles = null;

    CollisionDetector(){
        SpaceInvaders.theTicker.addTimed(this);
    }

    public void addAlien(Sprite a) {
        aliens = ImmutableList.add(aliens,a);
    }

    public void removeAlien(Sprite a) {
        aliens = ImmutableList.remove(aliens,a);
    }

    public void addMissile(Sprite m) {
        missiles = ImmutableList.add(missiles,m);
    }

    public void removeMissile(Sprite m) {
        missiles = ImmutableList.remove(missiles,m);
    }

    public void pretick(){
      Enumeration e = ImmutableList.elements(aliens);
      while(e.hasMoreElements()){
        Sprite alien = (Sprite)e.nextElement();
        if (alien.collide(SpaceInvaders.ship)) {
            SpaceInvaders.ship.hit();
            alien.hit();
        }
        Enumeration m = ImmutableList.elements(missiles);
        while(m.hasMoreElements()){
            Sprite missile = (Sprite)m.nextElement();
            if (alien.collide(missile)) {
                alien.hit();
                missile.hit();
            }
        }
      }
    }

    public void tick() {}
}
Previous