We’re here to help you

Menu

What can 'blocking' be Used For?

For the examples in this chapter, a snapshot containing Dezyne models and C++ source code is available on Github.

In the tutorial on the usage of the ‘external’ keyword, we successfully implemented a RobustTimer component that maps an ‘external’ requires ITimer port to a regular provides ITimer port. In order to fully capture the possible behaviours that occur when considering the port to be ‘external’, an extra out-event was added to mark the end of the cancellation transaction:

Before

After

interface ITimer {
  extern long_integer $long$;
  enum State { Idle, Running, Stopping };
  in void start(long_integer milliseconds);
  in void cancel();
  out void timeout();

  behaviour {
    State state = State.Idle;

    [state.Idle] {
      on start: state = State.Running;
      on cancel: { }
    }

    [state.Running] {
      on start: illegal;
      on cancel: state = State.Idle;
      on inevitable: {
        state = State.Idle;
        timeout;
      }
    }
  }
}
interface ITimer {
  extern long_integer $long$;
  enum State { Idle, Running, Stopping };
  in void start(long_integer milliseconds);
  in void cancel();
  out void timeout();
  out void cancelled();

  behaviour {
    State state = State.Idle;

    [state.Idle] {
      on start: state = State.Running;
      on cancel: { cancelled; }
    }

    [state.Running] {
      on start: illegal;
      on cancel: state = State.Stopping;
      on inevitable: {
        state = State.Idle;
        timeout;
      }
    }
    [state.Stopping] {
      on start: illegal;
      on cancel: illegal;
      on inevitable: {
        state = State.Idle;
        cancelled;
      }
    }
  }
}

This addition allowed the RobustTimer component to determine whether the ‘external’ requires port was free of any delayed timeout events. This was required to ensure that a new Timer could safely be started after cancelling an older one.

However, this change also had implications for other components that require ITimer ports. Originally, one of the reasons to create the RobustTimer component was to hide the complexity paired with ‘external’ behaviours from the Controller component. Ultimately, due to the changes made to the ITimer interface to accommodate for extra behaviours, we still had to make changes to the Controller component. Handling the asynchronous cancelled event had to be added to the behaviour of the Controller.

This phenomenon where changes lower down in the chain of command influence top-level components is what we will refer to as contagious asynchronicity. Because of asynchronous behaviour that was added to one of the lower components in the System, components higher up in the System are forced to accommodate for this asynchronous behaviour as well.

This is not always a bad thing- sometimes it is actually desired to propagate such events upwards so that perceived state of a subcomponent is updated. However, there are also cases where this additional information on the state of a subcomponent is irrelevant and as such, you do not want to deal with the added asynchronous behaviour of components. This is where ‘blocking’ comes into play; using ‘blocking’, it becomes possible to convert certain asynchronous behaviour patterns to synchronous versions.

In the case of the RobustTimer, ‘blocking’ will allow you to implement the cancellation process in such a way that it appears synchronous over the provides port even though it is asynchronous with respect to its requires port. In the next chapter, you will learn how to perform such an implementation.

If you have questions that weren’t answered by this Guide,
let our support team help you out.

Enjoy this article? Don't forget to share.