Recently, synchronous software architectures have been proposed specifically for reactive systems[11, 15]. The resulting synchronous/reactive systems include data-flow and declarative approaches as well as more traditional imperative languages. None of these approaches have proven intrinsically more powerful than the others, and an effort is currently underway to provide a common `back-end' for a number of these systems[15]. The typical reactive kernel for which the synchronous languages are intended has many properties of general system software. Many such kernels resemble stand-alone device drivers, that is, drivers running directly on the machine hardware without additional system support.
The synchrony hypothesis assumes that all computation occurs in discrete atomic steps during which time is ignored. This is often stated as the assumption that all program code executes in zero time. Time only advances when no code is eligible for execution. During a single step, all output is considered to occur at the same time as all step input, that is, output is synchronous with input. The notion of continuous time is thus replaced by an ordered series of discrete steps between which discrete changes occur in global state. The code executed at each step is called a reaction.
The fundamental advantage of this approach is that internal cooperative concurrency can be handled deterministically. Concurrent asynchronous events are manifested only within global state `snapshots'. No explicit critical sections occur in the source code, not even in the guise of monitors or concurrent objects, because all code can be considered inside implicit critical sections executed as required via guarded command style programming.
The synchronous/reactive languages focus on the internal cooperative concurrency commonly found in drivers and controllers. Synchronous languages essentially `compile away' all internal cooperative concurrency by producing a single deterministic state machine that manages all required activities. Nondeterministic external events are handled by the reaction dispatch or guard evaluation mechanism, and do not directly propagate into the body of the program. Because the single state machine into which concurrent programs are compiled cannot deadlock, the need for multiple threads, critical sections, and nondeterminacy is eliminated. However, synchronous languages that compile to a single state machine must sacrifice recursion and dynamic data allocation to obtain determinism.
Synchronous architectures somewhat resemble cyclic systems executing code repetitively using precomputed schedules. Synchronous approaches, however, see time as merely another discrete global state variable and only execute required reactions. Synchronous languages provide non-blocking and wait-free internal concurrency. A concurrent system is non-blocking if some member is guaranteed to complete an operation in a finite number of system steps. A system is wait-free if it can be guaranteed that each member completes an operation in a finite number of system steps[16]. Investigating alternatives to process-based concurrency is a current research area. For instance, processes are an artifact and need not be adopted as a fundamental primitive in theories of concurrency[17].
Figure 2: An NPL Routine