Preface

Concurrent and distributed programming are no longer the esoteric subjects for graduate students that they were years ago. Programs today are inherently concurrent or distributed, from event-based implementations of graphical user interfaces to operating and real-time systems to Internet applications like multiuser games, chats and ecommerce. Modern programming languages and systems (including Java, the system most widely used in education) support concurrent and distributed programming within their standard libraries. These subjects certainly deserve a central place in computer science education.

What has not changed over time is that concurrent and distributed programs cannot be “hacked.” Formal methods must be used in their specification and verification, making the subject an ideal vehicle to introduce students to formal methods. Precisely for this reason I find concurrency still intriguing even after forty years’ experience writing programs; I hope you will too.

I have been very gratified by the favorable response to my previous books Principles of Concurrent Programming and the first edition of Principles of Concurrent and Distributed Programming. Several developments have made it advisable to write a new edition. Surprisingly, the main reason is not any revolution in the principles of this subject. While the superficial technology may change, basic concepts like interleaving, mutual exclusion, safety and liveness remain with us, as have the basic constructs used to write concurrent programs like semaphores, monitors, channels and messages. The central problems we try to solve have also remained with us: critical section, producer–consumer, readers and writers and consensus. What has changed is that concurrent programming has become ubiquitous, and this has affected the choice of language and software technology.

Language: I see no point in presenting the details of any particular language or system, details that in any case are likely to obscure the principles. For that reason, I have decided not to translate the Ada programs from the first edition into Java programs, but instead to present the algorithms in pseudocode. I believe that the high-level pseudocode makes it easier to study the algorithms. For example, in the Byzantine Generals algorithm, the pseudocode line:

for all other nodes

is much easier to understand than the Java lines:

for (int i = 0; i < numberOfNodes; i++)
   if (i != myID)

and yet no precision is lost.

In addition, I am returning to the concept of Principles of Concurrent Programming, where concurrency simulators, not concurrent programming languages, are the preferred tool for teaching and learning. There is simply no way that extreme scenarios—like the one you are asked to construct in Exercise 2.3—can be demonstrated without using a simulator.

Along with the language-independent development of models and algorithms, explanations have been provided on concurrency in five languages: the Pascal and C dialects supported by the BACI concurrency simulator, Ada[1] and Java, and Promela, the language of the model checker Spin. Language-dependent sections are marked byL. Implementations of algorithms in these languages are supplied in the accompanying software archive.

A word on the Ada language that was used in the first edition of this book. I believe that—despite being overwhelmed by languages like C++ and Java—Ada is still the best language for developing complex systems. Its support for concurrent and real-time programming is excellent, in particular when compared with the trials and tribulations associated with the concurrency constructs in Java. Certainly, the protected object and rendezvous are elegant constructs for concurrency, and I have explained them in the language-independent pseudocode.

Model checking: A truly new development in concurrency that justifies writing a revised edition is the widespread use of model checkers for verifying concurrent and distributed programs. The concept of a state diagram and its use in checking correctness claims is explained from the very start. Deductive proofs continue to be used, but receive less emphasis than in the first edition. A central place has been given to the Spin model checker, and I warmly recommend that you use it in your study of concurrency. Nevertheless, I have refrained from using Spin and its language Promela exclusively because I realize that many instructors may prefer to use a mainstream programming language.

I have chosen to present the Spin model checker because, on the one hand, it is a widely-used industrial-strength tool that students are likely to encounter as software engineers, but on the other hand, it is very “friendly.” The installation is trivial and programs are written in a simple programming language that can be easily learned. I have made a point of using Spin to verify all the algorithms in the book, and I have found this to be extremely effective in increasing my understanding of the algorithms.

An outline of the book: After an introductory chapter, Chapter 2 describes the abstraction that is used: the interleaved execution of atomic statements, where the simplest atomic statement is a single access to a memory location. Short introductions are given to the various possibilities for studying concurrent programming: using a concurrency simulator, writing programs in languages that directly support concurrency, and working with a model checker. Chapter 3 is the core of an introduction to concurrent programming. The critical-section problem is the central problem in concurrent programming, and algorithms designed to solve the problem demonstrate in detail the wide range of pathological behaviors that a concurrent program can exhibit. The chapter also presents elementary verification techniques that are used to prove correctness.

More advanced material on verification and on algorithms for the critical-section problem can be found in Chapters 4 and 5, respectively. For Dekker’s algorithm, we give a proof of freedom from starvation as an example of deductive reasoning with temporal logic (Section 4.5). Assertional proofs of Lamport’s fast mutual exclusion algorithm (Section 5.4), and Barz’s simulation of general semaphores by binary semaphores (Section 6.10) are given in full detail; Lamport gave a proof that is partially operational and Barz’s is fully operational and difficult to follow. Studying assertional proofs is a good way for students to appreciate the care required to develop concurrent algorithms.

Chapter 6 on semaphores and Chapter 7 on monitors discuss these classical concurrent programming primitives. The chapter on monitors carefully compares the original construct with similar constructs that are implemented in the programming languages Ada and Java.

Chapter 8 presents synchronous communication by channels, and generalizations to rendezvous and remote procedure calls. An entirely different approach discussed in Chapter 9 uses logically-global data structures called spaces; this was pioneered in the Linda model, and implemented within Java by JavaSpaces.

The chapters on distributed systems focus on algorithms: the critical-section problem (Chapter 10), determining the global properties of termination and snapshots (Chapter 11), and achieving consensus (Chapter 12). The final Chapter 13 gives an overview of concurrency in real-time systems. Integrated within this chapter are descriptions of software defects in spacecraft caused by problems with concurrency. They are particularly instructive because they emphasize that some software really does demand precise specification and formal verification.

A summary of the pseudocode notation is given in Appendix A. Appendix B reviews the elementary mathematical logic needed for verification of concurrent programs. Appendix C gives a list of well-known problems for concurrent programming. Appendix D describes tools that can be used for studying concurrency: the BACI concurrency simulator; Spin, a model checker for simulating and verifying concurrent programs; and DAJ, a tool for constructing scenarios of distributed algorithms. Appendix E contains pointers to more advanced textbooks, as well as references to books and articles on specialized topics and systems; it also contains a list of websites for locating the languages and systems discussed in the book.

Audience: The intended audience includes advanced undergraduate and beginning graduate students, as well as practicing software engineers interested in obtaining a scientific background in this field. We have taught concurrency successfully to high-school students, and the subject is particularly suited to non-specialists because the basic principles can be explained by adding a very few constructs to a simple language and running programs on a concurrency simulator. While there are no specific prerequisites and the book is reasonably self-contained, a student should be fluent in one or more programming languages and have a basic knowledge of data structures and computer architecture or operating systems.

Advanced topics are marked byA. This includes material that requires a degree of mathematical maturity.

Chapters 1 through 3 and the non-A parts of Chapter 4 form the introductory core that should be part of any course. I would also expect a course in concurrency to present semaphores and monitors (Chapters 6 and 7); monitors are particularly important because concurrency constructs in modern programming languages are based upon the monitor concept. The other chapters can be studied more or less independently of each other.

Exercises: The exercises following each chapter are technical exercises intended to clarify and expand on the models, the algorithms and their proofs. Classical problems with names like the sleeping barber and the cigarette smoker appear in Appendix C because they need not be associated with any particular construct for synchronization.

Supporting material: The companion website contains an archive with the source code in various languages for the algorithms appearing in the book. Its address is:

http://www.pearsoned.co.uk/ben-ari.

Lecturers will find slides of the algorithms, diagrams and scenarios, both in ready-to-display PDF files and in LATEX source for modification. The site includes instructions for obtaining the answers to the exercises.

Acknowledgements: I would like to thank:

  • Yifat Ben-David Kolikant for six years of collaboration during which we learned together how to really teach concurrency;

  • Pieter Hartel for translating the examples of the first edition into Promela, eventually tempting me into learning Spin and emphasizing it in the new edition;

  • Pieter Hartel again and Hans Henrik L∅vengreen for their comprehensive reviews of the manuscript;

  • Gerard Holzmann for patiently answering innumerable queries on Spin during my development of jSpin and the writing of the book;

  • Bill Bynum, Tracy Camp and David Strite for their help during my work on jBACI;

  • Shmuel Schwarz for showing me how the frog puzzle can be used to teach state diagrams;

  • The Helsinki University of Technology for inviting me for a sabbatical during which this book was completed.

M. Ben-Ari

Rehovot and Espoo, 2005



[1] All references to Ada in this book are to Ada 95.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.186.219