The Dezyne language semantics assumes that at most one thread is active in a component at any time. If you are working in a purely single-threaded environment where no exceptions in the thread execution model of your application exist, this condition is easily met. However, most applications will probably end up containing some thread concurrency. At this point, you need to implement a thread safety mechanism to ensure that data remains valid and no concurrent (thread) access takes place while Dezyne logic is being executed.
The easiest way to do this in Dezyne is to generate a thread-safe-shell for your System component. This thread-safe-shell will wrap its internal components in such a way that every function call is placed in an event queue. This event queue is generated with the thread-safe-shell and ensures that events are handled one-by-one in a private thread. Foreign code can interact with the System on its ports like normal, but interactions are placed in the event queue and processed by the private thread.
The generation of a thread-safe-shell can be done using the command-line client and the following command:
dzn code -l c++ -s SYSTEM FILE
The above command will generate a thread-safe-shell for the System named
SYSTEM that is defined in FILE. For the System, *.cc
and *.hh files will be generated with some key differences to
their counterparts that were generated without the
--s option. In
*.hh, the System struct now contains a
dzn::pump is the object that represents the private
thread and the associated event queue. In *.cc, the constructor
for the System now also implements wrapper functions so that incoming
events are handled by the
dzn::pump thread instead of the calling
thread. (Incoming events should be seen from the perspective of
the System, so in-events on a provides port or out-events on a requires
Earlier in the section you were told that calling the timeout() function of the iTimer port is not safe by default (Timer and Siren integration). Calling an event from a signal handler is not safe by default. Signal handlers are similar to interrupt-service routines in the sense that they can be called while the process is involved in another function call.
With the default method of generating code from your System component, you run the risk of multiple active threads in the System. By generating a thread-safe-shell variant of the System, however, invoking the timeout event on the iTimer port will place the event in the event queue where it will be handled by the Dezyne private thread. With this change, thread safety is ensured without requiring any changes other than the code generation method. The easiest way to make the change is to add the following rule to the ‘generate’ make recipe:
generate: $(wildcard *.dzn) for f in $^; do dzn -v code --version=$(VERSION) -l c++ -o $(SRC) --depends=.d $$f; done dzn -v code --version=$(VERSION) -l c++ -o $(SRC) -s $(SYSTEMNAME) $(SYSTEMFILE) --depends=.d touch $
SYSTEMNAME and SYSTEMFILE are variables that should be defined in the makefile.