Real-time control implies that programmed systems must respond without fail in a discrete interval of time. A robot arm in motion, for example, must receive and process directional commands to avoid an obstacle that a vision system has detected in its path. A missile-guidance system must respond to deflection from programmed attitude and course and return the missile to its original flight path, or risk being destroyed. In both cases, failure to consider real-world information can be catastrophic.
Multitasking-systems designers have long relied upon the "patience" factor to hedge on access to resources, often through the use of magic constants.
In general, processor and memory resources are granted on a demand basis: The aggregate amount of resources in use at any time determines the time to obtain additional resources. "Fair" access to resources amounts to a flat rate per unit of resource; thus, larger consumers are subsidized by smaller consumers. To level this disparity, a systems designer can create a "use tax," allowing smaller consumers access to their meager resource needs without risk of being bumped. Consequently, a general-purpose operating system unilaterally regulates resource assignment by accumulating resource-usage statistics. Like a public utility, an operating system meters usage to a community of programs, processes, and tasks. When overtaxed, a "brownout" occurs, resulting in delayed access to resources. Service is provided on a "best-efforts basis" with no guarantee of performance.
However, certain types of service must be provided at all times. This is where real-time systems, on the whole, are different: A real-time program must be able to barter for processor resources, guaranteeing service. Instead of evaluating scheduling by implicit observed characteristics, real-time programming systems explicitly schedule resources via program requests. These and other program requests are the basis of POSIX.4 extensions.
Gallmeister provides a set of programming exercises for each chapter; solution programs appear in an appendix (with no descriptions other than program comments). While this is adequate for self-study, a set of written questions and answers would have made the book useful for a course on real-time programming. In addition, a case example or two that apply the elements of POSIX.4 to a real-time application (beyond simple fragments and empirical timings) would have helped the reader understand how to employ competing mechanisms in POSIX.4. This is nit-picking, however. It is difficult to develop real-time programming-case examples, as they are usually specific to an arcane situation.
Another thing missing from POSIX.4: Programming for the Real World is a
discussion of when real-time primitives for interprocess communications (IPC)
use a filename in a potentially independent namespace for a rendezvous point
(not necessarily in the file system itself). These primitives are usually left
in the file system so that you don't have to replicate programs in
other independent namespaces to display them and their attributes. This design
choice (taken from POSIX message queues, which were made from the preceding
System V message queues, which in turn were pulled from the Columbus
Labs' UNIX variant) has significant ramifications. In fact, IPC
name
spaces in sockets are still an active topic.
All in all, however, POSIX.4: Programming for the Real World is an excellent introduction to POSIX.4. As more of the real world runs on computers, strict, real-world programming requirements will be necessary. In fact, predictable quality may replace performance as the dominant industry and user concern.