QP/C  7.2.1
Real-Time Embedded Framework
No Matches
Active Objects

State MachinesEvent Delivery

As described in the Overview, the main goal of the QP Framework is to provide a lightweight and efficient implementation of the Active Object model of computation with the specific focus on deeply embedded real-time systems, such as single-chip microcontroller units (MCUs).

Active Objects in QP Framework

The diagram below shows a QP Application consisting of multiple, collaborating Active Objects that collectively deliver the desired functionality:

Figure 210 Active Objects in QP

Each Active Object has its own event queue and receives all events exclusively through that queue. On the other hand, events can be produced not only by Active Objects, but also interrupts (ISRs), or other software components. The Active Object infrastructure, such as the QP Framework in this case, is responsible for delivering and queuing the events in a deterministic and thread-safe manner.

The internal state machines of Active Objects have been described in the previous section. This section focuses on the internal event queues, threads and internal data of Active Objects.


Perhaps the most important characteristic of Active Objects, from which Active Objects actually derive their name, is their strict encapsulation. Encapsulation means that Active Objects don't share data or any other resources. Figure 210 illustrates this aspect by a thick, opaque encapsulation shell around each Active Object and by showing the internal state machines in gray, since they are really not supposed to be visible from the outside.

The QP Framework, especially when implemented in a programming language that does not support encapsulation (like C), cannot really guarantee the strict encapsulation of Active Objects. Achieving the encapsulation becomes then the responsibility of the QP Applications. But at the very least, the QP Framework needs to allow the QP Applications to avoid sharing of resources among the Active Objects.

Asynchronous Communication

All events are delivered to Active Objects asynchronously, meaning that an event producer merely posts an event to the event queue of the recipient Active Object but doesn't wait in line for the actual processing of the event.

The QP Framework makes no distinction between external events generated from interrupts and internal events originating from Active Objects. As shown in Figure 210, an Active Object can post events to any other Active Object, including to self. All events are treated uniformly, regardless of their origin.

Run-to-Completion (RTC)

Each Active Object processes events in run-to-completion (RTC) fashion, which must be guaranteed by the underlying QP Framework. RTC means that Active Objects process the events one at a time and the next event can only be processed after the previous event has been processed completely. RTC event processing is the essential requirement for proper execution of state machines.

No Blocking

Most traditional operating systems manage the threads and all inter-thread communication based on blocking, such as waiting on a time-delay or a semaphore. However, blocking (as in the middle of the RTC step) is incompatible with the RTC event processing requirement. This is because every blocking call is really another way to deliver an event (event is delivered by unblocking and return from a blocking call). Such "backdoor" event delivery happening in the middle of the RTC step violates the RTC semantics, because after unblocking the Active Object needs to process two events at a time (the original one and the new one delivered by unblocking).

Another detrimental consequence of blocking (or polling for events) inside RTC steps is that Active Objects become unresponsive to events delivered to their event queues. This, in turn, can cause Active Objects to miss their hard-real time deadlines and also can cause overflow of the event queue.

Finally, blocking (or polling for events) means that the expected sequences of events are hard-coded, which is inherently inflexible and not extensible, especially if new events need to be added or the system must handle multiple event sequences.

Thread of Control

In the UML, Active Object is defined as: "the object having its own thread of control" [UML 2.5]. This might indeed be the case if the QP Framework runs on top of a traditional multithreading kernel (e.g., traditional RTOS or general-purpose OS). However, the correct Active Object execution really requires the provision of a thread only during each RTC (Run-to-Completion) step. An Active Object that is merely waiting for event(s) does not need a thread at all. This opens up possibilities of using Active Objects with schedulers that don't support the notion of traditional threads. In that case Active Objects can collaborate in gaining access to the CPU only when needed.

It is very important to clearly distinguish the notion of RTC from the concept of preemption [OMG 07]. In particular, RTC does not mean that the Active Object thread has to monopolize the CPU until the RTC step is complete. In fact, RTC steps can be preempted by interrupts or other threads executing on the same CPU. Such thread preemption is determined by the scheduling policy of the underlying multitasking kernel, not by the Active Object model of computation. When the preempted Active Object is assigned the CPU time again, it resumes its event processing from the point of preemption and, eventually, completes its RTC step. As long as the preempting and the preempted threads don’t share any resources (see Encapsulation), there are no concurrency hazards.

Active Object Priority

In real-time applications it is very useful to prioritize work by assigning priorities to threads, for example. QP Framework takes it a bit further in that every Active Object is required to have a unique priority assigned to it. The Active Object priorities are then used as compact, unique identifiers of Active Objects.



QP Framework shall implement the Active Object design pattern


State MachinesEvent Delivery