Ada and Java: real-time advantages -

Ada and Java: real-time advantages


Ada and Java offer strengths for real-time programming and built-in support for multithreading. Join us for a look at what these two under-appreciated languages offer developers of embedded software.

Although C wins the popularity contest as the language most typically chosen for real-time embedded systems, other languages are worth considering. One of them, Ada, offers advantages over the C family, especially in high-reliability environments. Another, Java (as extended with real-time enhancements), may be especially attractive in highly dynamic systems.[1]

In this article, I'll review the language features you'll need for real-time and embedded applications and look at how C, Ada, and Java's real-time extensions address these requirements. I'll use a typical example to describe and compare the Ada and Java approaches. For summaries of Ada and Real-Time Java, see the Beginner's Corner articles listed as further reading at the end of this article.

What C ain't got
For reasons both technical and historical, C is the obvious choice for programming embedded applications. It is processor independent but low-level enough for programmers to get down and dirty with the machine. C can be implemented on almost every architecture imaginable, has reasonable run-time performance, is an international standard, and is familiar to almost all embedded systems programmers. Nonetheless, C has a number of drawbacks that may be significant:

  • Language insecurities. The loopholes in C's type model are well known; for example, allowing pointers to be treated as integral data and vice versa. Although it's possible to avoid such loopholes by adhering to a subset such as MISRA C or by applying a style-enforcement tool, more secure languages will prevent the hard-to-find bugs that loopholes create and will thereby decrease development time and promote higher reliability.
  • Lack of support for large-scale systems. C has weak facilities for “programming in the large,” that is, developing applications comprising hundreds of thousands, indeed perhaps millions of lines of code. A relatively small portion of most embedded systems needs the low-level facilities provided by C. The majority of the logic is higher-level processing that's better supported by languages that offer greater type safety and better capabilities for module structuring, namespace management, encapsulation, and object orientation.
  • Absence of needed functionality. C has no language support for concurrency (multithreading), a serious omission for real-time systems. The programmer needs to use an external application programming interface or real-time operating system (RTOS), thus compromising portability. The POSIX C binding, while addressing this concern to some degree, still leaves quite a bit of functionality implementation-dependent. Moreover, the programmer needs to be sensitive to whether otherwise-safe libraries can be used in a multithreaded application. Languages with an integrated concurrency model can better deal with these problems.

Language musts
Real-time embedded applications require the following:

  • General features for promoting reliability, maintainability, reusability, and other broad software engineering goals.
  • Specific features for real-time and embedded applications.
  • A lack of features that interfere with goals such as predictability of program execution and performance.

Examples of general-purpose features are compile-time type checking, support for encapsulation and information hiding, namespace management (avoiding clashes between the names of locally defined entities and either predefined or external entities), parameterizable templates, and object-oriented programming features. C's type checking is rather weak, and it offers no support for any of the other areas listed. In contrast, both Ada 95 and Java were designed from the outset to promote sound software engineering practices. Ada has somewhat more extensive capabilities than Java—for example, Ada supplies strongly typed scalars, operator symbol overloading, and generic templates.[2]

Several kinds of specialized features are required for real-time programming. For our purposes, we'll assume that a real-time system may be composed of a collection of periodic activities that cooperatively access shared resources, together with a set of activities that respond to external or software-initiated events. The programmer's job is to produce a system that satisfies various time-based metrics; for example, ensuring that all deadlines are met or that average throughput is optimized. Essential to this job is predictability of program execution. The relevant features include the following:

  • A thread/task model for expressing concurrent activities, mutual exclusion for shared resources, inter-thread or task coordination, and responses to asynchronous events including hardware interrupts.
  • Facilities for assigning priorities to threads/tasks and for establishing appropriate scheduling behavior (for example, controlling priority inversions).
  • Mechanisms for dealing with time: hardware clocks, timeouts, periodicity.

Since the C language lacks features for concurrency and has no support for these requirements, one solution is to directly invoke RTOS services for concurrency management. But that constrains the program to platforms that run that RTOS. Another approach is to use a POSIX binding, but the implementation flexibility permitted by POSIX also compromises portability. In contrast, both Ada and the Real-Time Specification for Java (RTSJ) include facilities for all of these real-time requirements.[3] Ada's tasking model is somewhat more sophisticated than the Java/RTSJ thread facility. For example, Ada's protected object/protected type mechanism for mutual exclusion with condition synchronization achieves good performance while also reflecting sound methodology (encapsulation).

On the other side, the real-time thread facility in the RTSJ is more dynamic and more flexible than Ada's. With the RTSJ, a programmer can define different priority-inversion control mechanisms for different shared objects and can supply different scheduling algorithms for different groups of real-time threads.

Beyond what is required for real-time programming, other features are needed for embedded systems development, such as the ability to program at the machine level (dealing with addresses and “raw storage”), write interrupt service routines, and execute similar functionality. This is where C does provide the needed features. Ada offers comparable functionality, specifically through its Systems Programming Annex. The Java language is (rightly) weak in this area, since the ability to directly access hardware resources would compromise both the language's safety and portability. The RTSJ addresses this concern in two ways. It allows “peeking” and “poking” of integral and floating-point data at specified addresses (“raw memory”), and it allows interrupt handlers to be expressed as handlers for asynchronous events.

Interestingly, more features don't automatically mean better functionality. If a language feature is more general than is required, there's the danger it may incur a run-time cost even if the feature is not used. Other features may interfere with the requirement for safety or predictability:

  • The ease with which type checking can be defeated in C is an example of unwanted generality that compromises reliability. The solution is for the programmer to adhere to certain stylistic guidelines (possibly detected/enforced by an external tool).
  • Ada has a general run-time model, and the full support may incur an unwanted cost. Anticipating such an issue, the language also includes a directive (pragma Restrictions ) that identifies features that aren't used by the program. A program that uses a feature that's excluded by pragma Restrictions is rejected by the compiler. The compiler's implementation can thus provide a specialized version of the run-time support—more efficient, perhaps even amendable to safety-critical certification—knowing that certain features will not be used.
  • The main issue with Java derives from its foundation in object-oriented programming. The problem isn't so much with efficiency—the overhead of dynamic binding needn't be more than an extra level of indirection on the method call—but rather with the apparent unpredictability or latency incurred by garbage collection. The approach taken in the RTSJ is to allow the program to define memory areas that aren't subject to garbage collection and to define certain kinds of threads that aren't allowed to access the garbage-collected heap; such threads may preempt the garbage collector.

Example: Sensor reporter
To help you grasp some of these concepts more thoroughly, here's an example of Ada and Java programming of a standard real-time embedded system: a sensor reporter. Figure 1 illustrates the main data flows among the various components of the sensor reporter.

Figure 1: Data flow in sensor reporter example

A sensor on a vehicle transmits position data (X and Y coordinates) 10 times per second. Each position value comprises a pair of signed 32-bit integers. Receipt is signaled to the CPU via a sensor input interrupt at level 31; the data is then available at the eight bytes located at hexadecimal addresses 100 through 107. X occupies locations 100 through 103, and Y is at locations 104 through 107. (Endianness issues are being ignored here.)

The input data are to be reported (displayed to the console) every 500ms, but this is not to begin until after the first input has come in. It's important that each displayed value be consistent (in other words, if new data are coming in while a position is being reported, it's not acceptable to display, for example, the old X and the new Y).

On request (triggered by the user entering a line starting with “?” at the keyboard), the program is to display the number of interrupts that have thus far occurred. When the user enters a line starting with “!” the program is to be terminated. Any other input from the user is ignored.

Although this example is simply stated, and although it omits details such as hardware initialization and fault detection/recovery, it's typical of many real-time embedded applications. It illustrates multithreading, interrupt handling, periodic behavior, access to low-level data, the need to protect shared data from simultaneous access by multiple threads of control, and the need for synchronization. It's therefore a useful example for comparing the features of candidate languages for such applications.

Listing 1 Ada version of sensor reporter

1 pragma Task_Dispatching_Policy(FIFO_Within_Priorities);
3 with Interfaces;
4 package Position_Pkg is
5  Sensor_Interrupt_Level : constant := 31;
7 protected Position is
8    procedure Sensor_ISR;
9    pragma Interrupt_Priority(Sensor_Interrupt_Level);
10    pragma Interrupt_Handler(Sensor_ISR);
11    pragma Attach_Handler(Sensor_ISR, Sensor_Interrupt_Level);
13    entry First_Fetch(X, Y: out Interfaces.Integer_32);
14    procedure Fetch(X, Y : out Interfaces.Integer_32);
15    function Num_Interrupts return Natural;
16 private
17    –protected components:
18    X, Y : Interfaces.Integer_32;
19    Count : Integer := 0;
20  end Position;
21 end Position_Pkg;
23 with System.Storage_Elements; use System.Storage_Elements;
24 package body Position_Pkg is
25  protected body Position is
26    procedure Sensor_ISR is
27       X, Y : Integer_32;
28       for X'Address use To_Address(16#100#);
29       for Y'Address use To_Address(16#104#);
30    begin
31       Position.X := X;
32       Position.Y := Y;
33       Count := Count+1;
34       –HW-specific processing here, e.g. reenabling interrupts
35    end Sensor_ISR;
37    entry First_Fetch(X, Y: out Integer_32) when Count > 0 is
38    begin
39       X := Position.X;
40       Y := Position.Y;
41    end First_Fetch;
43    procedure Fetch(X, Y : out Integer_32) is
44    begin
45       X := Position.X;
46       Y := Position.Y;
47    end Fetch;
49    function Num_Interrupts return Natural is
50    begin
51      return Count;
52    end Num_Interrupts;
53  end Position;
54 end Position_Pkg;
56 with Interfaces; use Interfaces;
57 with Ada.Text_IO; use Ada.Text_IO;
58 with Ada.Real_Time; use Ada.Real_Time;
59 with Position_Pkg; use Position_Pkg;
60 procedure Sensor_ISR_Reporter is
62   Shutdown : Boolean := False;
63   pragma Atomic(Shutdown);
65   task Position_Reporter is
66     pragma Priority(15);
67   end Position_Reporter;
69   task body Position_Reporter is
70     X : Integer_32;
71     Y : Integer_32;
73     Next_Time : Time;
74     Period : constant Time_Span := To_Time_Span(0.500); — .5 s
76   begin
77     Position.First_Fetch(X, Y);
78     Next_Time := Clock; — Function call
79     loop
80       Put(Integer_32'Image(X));
81       Put_Line(Integer_32'Image(Y));
82       Next_Time := Next_Time+Period;
83       delay until Next_Time;
84       exit when Shutdown;
85       Position.Fetch(X, Y); — Invoke protected operation
86     end loop;
87   end Position_Reporter;
89   task Count_Reporter is
90     pragma Priority(20);
91   end Count_Reporter;
93   task body Count_Reporter is
94     Char : Character;
95     Count : Natural;
96   begin
97     loop
98       Put(“Enter '?' to see statistics, '!' to quit: “);
99       Get(Char);
100       Skip_Line;
101       if Char = '?' then
102          Count := Position.Num_Interrupts;
103          Put_Line(“Count: ” & Integer'Image(Count));
104       elsif Char = '!' then
105          Shutdown := True;
106          exit;
107       end if;
108     end loop;
109   end Count_Reporter;
110 begin
111   null;
112 end Sensor_ISR_Reporter;

Ada explanation
The program (shown as Listing 1) comprises a pragma (an implementation directive) at Line 1, the specification (Lines 3 through 21) and body (Lines 23 through 54) for the package Position_Pkg , and a main procedure Sensor_ISR_Reporter (Lines 56 through 112). The package specification contains the interface of the package to other parts of the program; the package body contains the implementation.

pragma Task_Dispatching_Policy

The pragma at Line 1 establishes the task dispatching policy to be used by the run-time scheduler. FIFO_Within_Priorities means that when multiple tasks are ready to run, the task with highest priority is chosen. If several tasks are set at this priority, the one that has been waiting the longest is selected. This policy implies preemption: a higher-priority task awakening after a delay will preempt a lower-priority running task. Thus, informally, FIFO_Within_Priorities means “run until blocked or preempted.” An effect of FIFO_Within_Priorities is to establish the priority ceiling policy as the mechanism for managing object locking.

Position_Pkg Specification
The with clause on Line 3 identifies Interfaces as a module that is needed by Position_Pkg . Interfaces is a predefined package. It contains, among other things, the declaration of the 32-bit signed integer type Integer_32 referenced at Lines 13, 14, and 18.

The main content of Position_Pkg is the protected object Position (Lines 7 through 20). A protected object comprises “protected components” and “protected operations.” The term protected refers to the fact that the implementation needs to ensure mutually exclusive access to the object across multiple threads of control (tasks).[4] The protected components are declared in the private part of the object and are inaccessible except through the protected operations; thus, the protected object fully enforces encapsulation.

The three kinds of protected operations are all illustrated in the Position object. A protected procedure (Sensor_ISR, Fetch ) is allowed to “read” or “write” the protected components. A protected function (Num_Interrupts ) is allowed to read but not write the protected components. A protected entry (First_Fetch ) is similar to a protected procedure but has an accompanying “barrier condition” (Line 37) that is checked before the calling task is allowed to execute the entry body (Lines 38 through 41).

The various pragmas on Lines 9 through 11 relate to the protected object's usage for interrupt handling. The Interrupt_Priority pragma sets the “ceiling priority” for Position ; when any of the protected operations is invoked, the invoking task's priority will be raised to the value given (Sensor_Interrupt_Level ). In the case of the protected procedure Sensor_ISR , the invoker will not be a software task but rather an interrupt handling context.

If a task calls a protected operation (for example Line 77) it must first acquire the lock on the object; it releases the lock on completion of the operation. If the operation is a protected entry, then the calling task must acquire the lock before evaluating the entry barrier. If the barrier condition is true, the calling task simply executes the entry body. If the barrier condition is false, then the calling task is placed in a queue associated with the entry and it releases the lock on the object. At the end of a protected procedure or protected entry, the barrier conditions are evaluated for any entries with nonempty queues. For some such entry whose condition is now true, one of the waiting tasks is made ready, and the corresponding entry body is executed on behalf of that task, with the object still locked. The program can specify the entry queuing policy; by default it's FIFO. In this example the queuing policy is not relevant, since only one task (Position_Reporter ) is calling the First_Fetch entry.

Entry barriers are analogous to condition variables in POSIX but are at a higher level; an explicit signal isn't needed since it's done automatically as part of the barrier reevaluation.

The protected procedure Sensor_ISR (Lines 26 through 35) is invoked as the interrupt handler for the Sensor_Interrupt_Level interrupt; it updates the protected components X and Y and increments the protected component Count .

Position_Pkg Body
The package body contains the body of the protected object, which in turn contains the implementation of the protected operations. The logic for most of these operations should be relatively straightforward. The Sensor_ISR procedure fetches the values of the 32-bit integers stored at locations 100 and 104 and assigns them into the corresponding components of the protected object. The semantics of protected objects and priority ceilings prevent problems caused by nested interrupts.

The package System.Storage_Elements is “with”ed by Position_Pkg (Line 23) since the function To_Address is required. The use clause allows the code to reference this function without the System.Storage_Elements prefix that would otherwise be needed.

Sensor_ISR_Reporter Procedure
The main procedure declares two tasks, Position_Reporter (Lines 65 through 87) and Count_Reporter (Lines 89 through 109). Each task is assigned an explicit priority in its specification. Position_Reporter communicates with Count_Reporter via a shared Boolean variable Shutdown . pragma Atomic(Shutdown) at Line 63 checks that the Shutdown variable is atomically accessible (no chance of a task switch when the variable is being fetched or stored) and also inhibits the compiler from caching the variable in the local memory of the tasks that access it.

Both tasks are activated just after the “begin” of the enclosing procedure (Line 110). Position_Reporter waits until some data has been set by the interrupt handler (Line 77) and then periodically displays the Position components and fetches the next Position value. The loop is exited when Shutdown is true at Line 84. The periodicity idiom uses the absolute delay statement (Line 87) to implement the 500ms heartbeat.

The Count_Reporter task is expressed as a loop that displays a prompt, blocks until the user enters some input, and then interprets the input as required (displaying the count when the line begins with “?” and setting Shutdown and exiting when the line begins with “!”). Get(Char) inputs a character; Skip_Line flushes the input through the next end-of-line.

For simplicity, let's ignore the fact that the Position_Reporter and the Count_Reporter tasks may simultaneously call Put_Line (which may lead to intermixed output). There are several techniques for avoiding this situation, but these are beyond the scope of this article.

Real-time Java
The real-time Java version of the application comprises a main class (SensorReporterExample ), one class for the shared position object (Position ), one class for the interrupt handler (Sensor ), two classes for the threads that access the position object (PositionReporter, CountReporter ), and two “helper” classes (Shutdown, Latch ). Listing 2 shows an RTSJ version of a sensor reporter.

Listing 2 Real-time Java version of sensor reporter

class SensorReporterExample {

public static void main(String[] args) {

      Shutdown   sh = new Shutdown();
      PositionReporter   pr = new PositionReporter(sh);
      Sensor   s = new Sensor();
      CountReporter   cr = new CountReporter(sh);


class Latch {
  // simple event that, once signaled, remains set
  private boolean triggered = false;

  synchronized void await() {

      if (!triggered) { // no need for while
        try {
        catch (InterruptedException e) {

  synchronized void signal() {

      triggered = true;

class Position {

  static final Position INSTANCE = new Position(); // singleton
  private int x, y;
  private int count = 0;
  private final Latch L = new Latch();

  private Position() {}  // No externally available constructor

  synchronized void sensorIsr(int x, int y) {
      this.x = x;
      this.y = y;
      if (count==1) {L.signal();}

  static class Coordinates {
      int x;
      int y;

  synchronized void fetch(Coordinates xy) {
      xy.x = x;
      xy.y = y;

synchronized void firstFetch(Coordinates xy) {
      xy.x = x;
      xy.y = y;

  synchronized int numInterrupts() {
      return count;

import javax.realtime.*;

class Sensor extends AsyncEventHandler {
  private final RawMemoryAccess rma =
        new RawMemoryAccess(

            “RAM”,   // type of memory
            0x1000,   // base address
            8);   // size (in bytes)

  private final AsyncEvent dataArrival;

  public Sensor() {

        new PriorityParameters(
         PriorityScheduler.instance().getMaxPriority() – 1

      dataArrival = new AsyncEvent();

  public void handleAsyncEvent() {
      int x = rma.getInt(0);
      int y = rma.getInt(4);
      Position.INSTANCE.sensorIsr(x, y);

class Shutdown {
  volatile boolean shutdown = false;

import javax.realtime.*;

class PositionReporter extends RealtimeThread {
  private final Shutdown s

  PositionReporter(Shutdown s) {

        new PriorityParameters(
        PriorityScheduler.instance().getMinPriority() + 15 ),
        new PeriodicParameters(

          null,   // when to start (null means now)
          new RelativeTime(500, 0),   // 500 ms period
          new RelativeTime(20, 0),   // 20 ms cost
          new RelativeTime(500, 0),   // 500 ms deadline
          null,   // no overrun handler
          null )   // no miss handler

       this.s = s;
  public void run() {

      Position.Coordinates xy = new Position.Coordinates();

      if (!s.shutdown) {
        while (true) {
          System.out.println(xy.x + ” ” + xy.y);
          try {
          catch (InterruptedException e) {
          if (s.shutdown) {


class CountReporter extends Thread {

  private final Shutdown sh;

  CountReporter(Shutdown sh) { = sh;

  public void run() {

      Position.Coordinates xy = new Position.Coordinates();
      String s;

      while (true) {
        System.out.println(“Enter '?' to see statistics, ” +
             “'!' to quit: “);
        try {
          s = new BufferedReader(
              new InputStreamReader( ) ).readLine();
        catch (IOException e) {
          s = “”;
        if (s.length() > 0 && s.charAt(0) == '?') {
          int count = Position.INSTANCE.numInterrupts();
          System.out.println( count );
        else if (s.length() > 0 && s.charAt(0) == '!') {
          sh.shutdown = true;

SensorReporterExample class
The main method simply constructs the relevant objects and starts the threads. The Shutdown object is passed to the constructors for the two reporter classes, since it's used for communication between these two threads. The default thread dispatching policy, required by the RTSJ, is FIFO within priorities, and it also applies to threads waiting for a lock.

Latch class
This class implements a variation on the binary semaphore. When a thread invokes x.signal() on a Latch instance x , all threads currently blocked on a call of x.await() are awakened; moreover, no subsequent thread will be blocked when calling x.await() . A Latch is a useful mechanism for applications such as data initialization when one thread is responsible for performing the initialization and other threads need to block until the initialization has been completed but not thereafter.

Position class
Position is a singleton class —there's only one instance, given by the final static variable Position.INSTANCE . The private final Latch variable L simulates a condition variable; firstFetch awaits L being signaled, and sensorIsr signals L when count is 1. Note that you can use alternative styles that avoid doing the test (count==1) every time sensorIsr is called.

All of the methods in Position are synchronized, and the instance variables are private; thus the accesses to Position.INSTANCE from different threads will be executed with mutual exclusion.

Sensor class
The Sensor class illustrates the RTSJ approach to asynchronous event handling and access to raw memory. When a Sensor object is constructed an associated AsyncEvent is bound to the specified interrupt (InputInterrupt ), and the Sensor object itself is registered as an event handler. When the interrupt occurs, each registered handler (here just the Sensor object) is scheduled based on the parameters provided when the handler was constructed (here simply the defaults). The intent is that the interrupt handler can be lighter weight than a full thread. When the handler runs, its handleAsynEvent method is invoked. In this example, the effect is to fetch the values from the raw memory area created by the constructor (a block of RAM 8-bytes long at origin 0x1000), and to assign these into the Position object. The default mechanism for priority inversion avoidance is priority inheritance; since the Sensor has a high priority (one less than the maximum value), if the Position.INSTANCE object is locked, its owner will have its priority boosted to that of the Sensor .

Shutdown class
This class is used for communication between the PositionReporter and CountReporter objects. The specification of volatile is needed to prevent the compiler from caching the shutdown field in the local memory of either or both of the threads.

PositionReporter class
The PositionReporter class illustrates how to define a periodic thread in the RTSJ. PositionReporter extends RealtimeThread . One of the constructors for the latter class takes several kinds of parameters: SchedulingParameters (which can be used to assign a priority value), and ReleaseParameters . The latter has a subclass PeriodicParameters which defines the required behavior. The main parameter is the period, which is used by the waitForNextPeriod method, but cost and deadline parameters can also be used in connection with deadline-miss and budget-exceeded handlers.

CountReporter class
The CountReporter class simply extends Thread (rather than RealtimeThread ). It's a loop that prompts for and reads a string and then takes appropriate action based on the first character: display the number of interrupts (if “?”), set the shutdown flag (if “!”), or just ignore the input (anything else).

Freedom of choice
Developers of real-time and embedded applications have a number of alternatives for their programming language. Although C may seem an obvious choice, the C standard has errors of omission. It lacks required functionality such as a standard thread/concurrency model, it doesn't readily scale up to large applications, and it has loopholes and insecurities that interfere with reliability.

Ada and the RTSJ address these concerns. Between the two, Ada has a more traditional run-time model, a somewhat more comprehensive concurrency facility, and existing implementations. Perhaps the main drawback of Ada is not technical but the fact that it's not as well known or as widely used as its competitors.The advantages of the RTSJ are its flexibility and extensibility. Its main drawback is that users will need to be much more aware of memory management issues than if they were using Ada or non-real-time Java. Also, as a newer technology, the RTSJ is not as widely implemented as more mature languages like C and Ada. However, this gap is likely to become narrower in the future, since the RTSJ's innovations are attracting considerable attention from the user community, especially in areas where dynamic flexibility is required. Java, as augmented by the RTSJ, thus has the potential to be the first language to make object-oriented programming a reality in real-time systems.

Ben Brosgol is a senior member of the technical staff at Ada Core Technologies. He was a primary member of the team that designed the Real-Time Specification for Java and is currently on the Technical Interpretation Committee. He has a PhD in applied mathematics from Harvard. Contact him at .

Further reading
Brosgol, Benjamin M, “Ada 95,” Beginner's Corner, Embedded Systems Programming , January 2003, pp. 39-40.

Brosgol, Benjamin M, “Real-Time Java,” Beginner's Corner, Embedded Systems Programming , May 2003, pp. 39-40.

1. Two independent efforts are actually aimed at extending Java with real-time capabilities: the Real-Time Specification for Java (RTSJ), developed under Sun Microsystems' Java Community Process, and the Core Extensions, developed by the J-Consortium independently from the JCP. This article focuses on the RTSJ, which has a working Reference Implementation.

2. Work is in progress on adding generics (templates) to Java, and this facility is planned for inclusion in Java 1.5. See JSR-000014, “Adding Generics to the Java Programming Language,”

3. Note that both Ada and the RTSJ may be implemented on top of an RTOS. Indeed, both were designed with that goal in mind. On the other hand, neither requires the presence of an RTOS. On a “bare machine,” the implementation will be responsible for managing threads.

4. More accurately, the model is “Concurrent Read, Exclusive Write” since simultaneous access to operations that simply fetch components is permitted.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.