The architecture of concurrent programs
Authors: Per Brinch Hansen
Venue:  (1977)

From the Preface CONCURRENT PROGRAMMING This book describes a method for writing concurrent computer programs of high quality. It is written for professional programmers and students who are faced with the complicated task of building reliable computer operating systems or real-time control programs. The motivations for mastering concurrent programming are both economic and intellectual. Concurrent programming makes it possible to use a computer where many things need attention at the same time--be they people at terminals or temperatures in an industrial plant. It is without doubt the most difficult form of programming. This book presents a systematic way of developing concurrent programs in a structured language called Concurrent Pascal--the first of its kind. The use of this language is illustrated by three non-trivial concurrent programs: a single-user operating system, a job-stream system, and a real-time scheduler. All of these have been used successfully on a PDP 11/45 computer. The book includes the complete text of these three programs and explains how they are structured, programmed, tested, and described. In an earlier book, Operating System Principles [Prentice-Hall, 1973], I tried to establish a background for studying existing operating systems in terms of basic concepts. This new text tells the other side of the story: how concurrent programs can be constructed systematically from scratch. It also illustrates details of important design problems--the management of input/output, data files, and programs--which were deliberately omitted from the first book. So it is useful both as a practical supplement to operating system courses and also as a handbook on structured concurrent programming for engineers. COMPILATION AND TESTING A concurrent program consists of sequential processes that are carried out simultaneously. The processes cooperate on common tasks by exchanging data through shared variables. The problem is that unrestricted access to the shared variables can make the result of a concurrent program dependant on the relative speeds of its processes. This is obvious if you think of a car and a train passing through the same railroad crossing : it is the relative timing of these "processes" that determines whether they will collide. Unfortunately, the execution speed of a program will vary somewhat from one run to the next. It will be influenced by other (unrelated) programs running simultaneously and by operators :responding to requests. So you can never be quite sure what an incorrect, concurrent program is going to do. If you execute it many times with the same data you will get a different result each time. This makes it hopeless to judge what went wrong. Program testing is simply useless as a means of locating time-dependent errors. Some of these errors can no doubt be located by proofreading. I have seen a programmer do this by looking at an assembly language program for a week. But, to proofread a large program, you must understand it in complete detail. So the search for an error may involve all of the people who wrote the program, and even then you cannot be sure it will be found. Well, if we cannot make concurrent programs work by proofreading or testing, then I can see only one other effective method at the moment: to write all concurrent programs in a programming language that is so structured that you can specify exactly what processes can do to shared variables and depend on a compiler to check that the programs satisfy these assumptions. Concurrent Pascal is the first language that makes this possible. In the long run it is not advisable to write large concurrent programs in machine-oriented languages that permit unrestricted use of store locations and their addresses. There is just no way we will be able to make such programs reliable (even with the help of complicated hardware mechanisms). CONCURRENT PASCAL From 1963-65 I was one of ten programmers who wrote a Cobol compiler in assembly language. This program of 40,000 instructions took 15 man-years to build. Although it worked well, the compiler was very difficult to maintain since none of us understood it completely. Five years later, compiler writing was completely changed by the sequential programming language Pascal, invented by Niklaus Wirth. Pascal is an abstract language that hides irrelevant machine detail from the programmer. At the same time it is efficient enough for system programming. It is easily understood by programmers familiar with Fortran, Algol 60, Cobol, or PL/I. In 1974 A1 Hartmann used Sequential Pascal to write a compiler for my new programming language, called Concurrent Pascal. This compiler is comparable to a machine program of 35,000 instructions. But, written in Pascal, the program text is only 8,300 lines long and can be completely understood by a single person. The programming and testing of this compiler took only 7 months. The aim of Concurrent Pascal is to do for operating systems what Sequential Pascal has done for compilers: to reduce the programming effort by an order of magnitude. Concurrent Pascal extends Sequential Pascal with concurrent processes and monitors. The compiler prevents some time-dependent programming errors by checking that the private variables of one process are inaccessible to another. Processes can only communicate by means of monitors. A monitor defines all the possible operations on a shared data structure. It can, for example, define the send and receive operations on a message buffer. The compiler will check that processes only perform these two operations on a buffer. A monitor can delay processes to make their interactions independent of their speeds. A process that tries to receive a message from an empty buffer will, for example, be delayed until another process sends a message to it. If a programmer can design a process or monitor correctly, the rest of a program will not be able to make that component behave erratically (since no other part of the program has direct access to the variables used by a component). The controlled access to private and shared variables greatly reduces the risk of time-dependent program behavior caused by erroneous processes. MODEL OPERATING SYSTEMS This book stresses the practice of concurrent; programming. It contains a complete description of three model operating systems written in Concurrent Pascal. Chapter 5 describes a single-user operating system, called Solo. It supports the development of Sequential and Concurrent Pascal programs on the PDP 11/45 computer. Input/output are handled by concurrent processes. Pascal programs can call one another recursively and pass arbitrary parameters among themselves. This makes it possible to use Pascal as a job control language. Solo is the first major example of a hierarchical concurrent program made of processes and monitors. Chapter 6 presents a job-stream system that compiles and executes short Pascal programs which are input from a card reader and are output on a line printer. Input, execution, and output take place simultaneously, using buffers stored on disk. Chapter 7 discusses a real-time scheduler for process control applications in which a fixed number of concurrent tasks are carried out periodically with frequencies chosen by an operator. These chapters not only describe how to build different kinds of operating systems but also illustrate the main steps of the program development process. The Solo system shows how a concurrent program of more than a thousand lines can be structured and programmed as a sequence of components of less than one page each. The real-time scheduler is used to demonstrate how a hierarchical, concurrent program can be tested systematically. The job-stream system illustrates how a program structure can be derived from performance considerations. LANGUAGE DEFINITION AND IMPLEMENTATION I have tried to make this book as readable as possible to share an architectonic view of concurrent programming effectively. Formalism is often a stumbling block in the first encounter with a new field, and the practice of structured concurrent programming is not commonplace yet. So I have assumed in chapters 3 and 4 that you are so familiar with one or more programming languages that it is sufficient to show the flavor of Sequential and Concurrent Pascal by examples before describing the model operating systems. But when you wish to use a new programming language in your own work, a precise definition of it becomes essential. So the Concurrent Pascal report is included in chapter 8. The whole purpose of this work is to show how much a concurrent programming effort can be reduced by using an abstract language that suppresses as much machine detail as one can afford to without losing control of program efficiency. For this reason the introduction to Concurrent Pascal ignores the question of how the language is implemented. Chapter 9 is an overview of the language implementation for those who feel uncomfortable unless they have a dynamic feeling for what their programs make the machine do. I suspect that most of us belong to that group. Once you understand what a machine does, however, it is easier to forget the details again and start relying completely on the abstract concepts that are built into the language. TEACHING AND ENGINEERING Very few operating systems are so well-structured and well-documented that they are worth studying in detail. And few (if any) computing centers make it possible for students to write their own concurrent programs in an abstract language. Since students can neither study nor build realistic operating systems it is almost impossible to make them feel comfortable about the subject. This book tries to remedy that situation. It defines an abstract language for concurrent programming that has been implemented on the PDP 11/45 computer. The compiler can be moved to other computers since it is written in Sequential Pascal and generates code for a simple machine that can be simulated efficiently by microprogram or machine language. The book also offers complete examples of model operating systems that can be studied by students. If you are a professional programmer you can seldom choose your own programming language for large projects. But you can benefit from new language constructs--such as processes and monitors--by taking them as models of a systematic programming style that can be imitated as closely as possible in other languages (including assembly languages). The system kernel that is described in chapter 9 illustrates this. It is an assembly language program written entirely by means of classes (a concept similar to monitors). Since this concept is not in the assembly language it is described by comments only. The book can also be used as a handbook on the design of small operating systems and significant portions of larger ones. If you are a software engineer you may feel that the operating systems described here are much smaller than those you are asked to build. This raises the question of whether the concepts used here can help you build huge systems. My recommendation is to use abstract programming concepts (such as processes and monitors) wherever you can. 'This will probably solve most programming problems in a simple manner and leave you with only a few really machine-dependent components (such as a processor scheduler and a storage allocator). As a means of organizing :your thoughts, Concurrent Pascal can only be helpful. But I should also admit that I do not see a future for large operating systems. They never worked well and they probably never will. They are just too complicated for the human mind. They were the product of an early stage in which none of us had a good feeling for what software quality means. The new technology that supports wide-spread use of cheap, personal computers will soon make them obsolete. Although operating systems have provided the most spectacular examples of the difficulty of making concurrent programs reliable, there are other applications that present problems of their own. As an industrial programmer I was involved in the design of process control programs for a chemical plant, a power plant, and a meteorological institute. These realtime applications had one thing in common: they were all unique in their software requirements. When the cost of developing a large program cannot be shared by many users the pressure to reduce the cost is much greater than it is for generalpurpose software, such as compilers and operating systems. The only practical way of reducing cost then is to give the process control engineers an abstract language for concurrent programming. To illustrate this I rewrote an existing real-time scheduler from machine language into Concurrent Pascal (chapter 7). The recent reduction of hardware costs for microprocessors will soon put even greater pressure on software designers to reduce their costs as well. So there is every reason for a realistic programmer to keep an eye on recent developments in programming methodology. PROJECT BACKGROUND In 1971, Edsger Dijkstra suggested that concurrent programs might be easier to understand if all synchronizing operations on a shared data structure were collected into a single program unit (which we now call a monitor). In May 1972 I wrote a chapter on Resource Protection for Operating System Principles. I introduced a language notation for monitors and pointed out that resource protection in operating systems and type checking in compilers are solutions to the same problem: to verify automatically that programs only perform meaningful operations on data structures. My conclusion was that "I expect to see many protection rules in future operating systems being enforced in the cheapest possible manner by type checking at compile time. However, this will require exclusive use of efficient, well-structured languages for programming." This is still the idea behind Concurrent Pascal. I developed Concurrent Pascal at the California Institute of Technology from 1972-75. The compiler was written by A1 Hartmann. Robert Deverill and Tom Zepko wrote the interpreter for the PDP 11/45. I built the model operating systems, and Wolfgang Franzen made improvements to one of them (Solo).