Vous êtes sur la page 1sur 160

Principles of

Concurrent
Programming

M . Ben-Ari
Tel-Aviv University

Englewood C liff*. Now Jersey


Singapore
Sydney
Tokyo

London
Toronto

N ew Delhi
W ellington

Library of C o n g ress C ataloging in P ublication Data


Ben-Ari, M.,
1948Principles of concurrent program m ing.
Bibliography: p.
Includes index.
1. Parallel processing (Electronic com puters)
L Title
QA76.6.B437
001.64'2
62-3650
ISBN 0-13-701078-8 (pbk.)
AACR2

British Library C atalo g u in g in Publication D ata


Ben-Ari, M.

Principles of concurrent program m ing.


1. Parallel processing (Electronic com puters)
2. O perating sy stem s (Computers)
I. Title
001.64'25
QA76.6
ISBN 0-13-701078-8

0 1 9 8 2 by PRENT1CE-HALL INTERNATIONAL, INC.


All rights reserved. No p art of this publication m ay b e reproduced, sto red in a
retrieval system , or transm itted, in any form or by a n y m eans, electronic,
m echanical, photocopying, recording o r otherw ise, w ithout th e prior perm ission
of Prentice-Hall International, Inc.
For perm ission within th e United S ta te s contact Prentice-Hall Inc, Englew ood
Cliffs, N.J. 07632.

ISBN

0-13-?010?fi-A

PRENTICE-HALL INTERNATIONAL INC., L ondon


PRENTICE -HALL OF AUSTRALIA PTY., LTD.. S ydney
PRENTICE-HALL CANADA, INC.. Toronto
PRENTICE-HALL OF INDIA PRIVATE LIMITED. N ew Delhi
PRENTICE-HALL OF JAPAN. INC., Tokyo
PRENTICE-HALL OF SOUTHEAST ASIA PTE , LTD., S in g ap o re
PRENTICE-HALL INC.. E nglew ood Cliffs, N ew J e rs e y
WHITEHALL BOOKS LIMITED. W ellington. N ew Z ealand

Printed in th e U nited S ta te s o f A m erica

109876543

CONTENTS

Preface

xiii

A cknow ledgem ents

xv

W hat Is C oncurrent Program m ing?


1.1
1.2
1.3
1.4
1.5
1.6
1.7
1.8
1.9

From Sequential to Concurrent Programming 1


Concurrent Programming 4
Correctness of Concurrent Programs 6
Interleaving 7
The Origin of Operating Systems 8
Operating Systems and Concurrent Programming
An Overview of the Book
12
Program Notation 14
Exercises 16

The C oncurrent Program m ing A bstraction


2.1
2.2
2.3
2.4
2.5
2.6
2.7
2.8

18

Introduction
18
Mutual Exclusion 19
Correctness 20
Timing 22
Implementing Primitive Instructions 24
Concurrent Programming in Pascal*S 26
Summary 27
Exercises 28

10

CO N ItN TS

The M utual Exclusion Problem

29

3.1 Introduction 29
3.2 First Attem pt 30
3.3 Second Attempt 32
3.4 Third Attempt 34
3.5 Fourth Attempt 36
3.6 D ekkers Algorithm 38
3.7 A Proof of Dckkers Algorithm
3.8 Conclusion 43
3.9 F.xereises 43

S em aphores

40

SO

-..1

M u iu a i tA ^iusior.

4.3
4.4
4.5
4.6
4.7

The Producer-Consumer Problem 36


More on the Producer-Consumer Problem
The Sleeping Barber 62
The Bounded Buffer 65
Exercises 68

M onitors
5.1
5.2
5.3
5.4
5.5
5.6
5.7
5.8

58

73

Introduction 73
Definition of Monitors 75
Simulation of the Semaphore 78
The Readers and Writers Problem 80
Proving Properties of Monitors 83
The Simulation of Monitors by Semaphores
Unrestricted Signals 88
Exerciscs 90

The Ada R endezvous


6.1
6.2
6.3
6.4
6.5

5!

93

Introduction 93
The Accept Statement 94
The Select Statement 99
Proving Properties of the Rendezvous
Exerciscs 105

105

86

CONTE N'IS

T h e D in in g P h ilo s o p h e r s

109

7.1 Introduction 109


7.2 First A ttem pt 110
7.3 Sccond Attem pt 1 11
7.4 A Correct Solution
113
7.5 Conditional Critical Regions
7.6 Exercises 117
A p p e n d ix : I m p le m e n ta tio n Kit

A. I
A.2
A.3
A.4
A .5
A.6
A .7
A.#

fnlrodiicljun 119
The Compiler 120
The P-Code 121
Procedure Calls 124
Concurrency 129
Semaphores 132
Random ^aiion
133
Program Listing 133

Bibliography

165

Textbooks
165
Sources 165
Index

171

119

115

XI

PREFACE

C oncurrent program m ingthe program m ing tools and techniques for deal*
ing with parallel processes has traditionally been a topic in operating
systems theory texts. T h ere are several reasons why concurrent program
ming deserves a book o f its own and should be the core of an advanced
com puter science systems course:
1. C oncurrent program m ing is what distinguishes operating systems and
real-tim e systems from o th er software systems. C om puter scicnce stu
dents who have taken courses in program m ing, d ata structures, com pu
ter architecture and probability can easily m aster the applications of
these disciplines in operating systems, but they need to be introduced to
techniques that will enable them to deal with parallelism.
2 . I d o u b t if m a n y o f m y s t u d e n ts w ill e v e r d e s ig n o r c o n s tru c t a m u ltip ro
c e s sin g tim e -s h a r in g sy s te m w h e re a lg o r ith m s f o r p a g in g a n d sc h e d u lin g
a r e o f p rim e im p o r ta n c e . I a m c e r ta in th a t th e y w ill b e d e s ig n in g a n d
c o n s tru c tin g r e a M im e sy s te m s f o r m in i- a n d m ic r o c o m p u te rs . A s o u n d
k n o w le d g e o f c o n c u r r e n t p r o g ra m m in g w ill e n a b le th e m t o c o p e w ith
r e a l-tim e sy s te m s in p a r tic u la r w ith th e s e v e re re lia b ility r e q u ir e
m e n ts th a t a r e im p o s e d .

3. T here isa trend tow ards increasing use o f abstract concurrency that has
nothing to do with the parallelism o f actual systems. D ata flow diagrams
used in softw are engineering are nothing m ore than netw orks o f concur*
rent processes. T raditionally, such a design must be im plem ented in a
sequential language, but UNIX* is a program m ing system which
encourages the use of concurrent processes. Ada*, the new language
designed for the U.S. D epartm ent o f D efense, includes concurrent
program m ing features as an integral p art o f the language.
t U N IX is a tradem ark o f Bell L aboratories.
J A da is a trad em ark o f the U nited S tates D ept, o f Defense.
xiii

Kiv

PRbhACE

4. Finally, concurrcni program m ing is an im portant topic in com puter


science research. The basic results in th e field are still scattered
throughout the literature and deserve to be collected into one volume
for a new com er to the field.
The hook requires no prerequisites as such o th er than com puter science
m aturity (to borrow ilte term from m athem atics). The book is aim ed at
advanced undergraduate students of com puter science. A t the l e i Aviv
Univeristy. we arrange the course of study so that a student has four
sem esters o f com puter science courses which include extensive program
ming exercises. The m aterial is also appropriate for practicing systems and
real'iim e program m ers who are looking for a more formal treatm ent of the
tools of their trade.
I have used the matcriul for half of a weekly four-hour sem ester course
in operating systems the second half is devoted to the classical subjects:
memory m anagem ent, etc. I should like to see curricula evolve that would
devote a q u arter or trim ester to (theoretical) concurrent program m ing
followed by a project oriented course on operating systems or real-tim e
systems.
The book is not oriented to any particular system o r technique. 1 have
tried to give equal time to the most w idespread and successful tools for
concurrent programming: mem ory arbiters, sem aphores, m onitors and
rendezvous. Only the most elem entary features of Pascal and A da are used;
they should be understandable by anyone with experience in a m odern
piogram m ing language.
Much o f the presentation closely follows the original research articles
by E. W. D ijkstra and C. A . R. H oare. In particular, D ijkstra's Co-operating
Sequential Processes reads like a novel and it was always great fun to lecture
the m aterial. T his book is an attem pt to explain and expand on their work.
V erification of concurrcni program s is one o f (he most exciting areas of
research today. C oncurrent program s are notorious for the hidden and
sophisticated bugs they contain. Form al verification seem s indispensable.
A novel feature of this book is its attem pt to verify concurrent program s
rigorously though informally. Hopefully, a student who is introduced early to
verification will be prepared to study formal m ethods at a m ore advanced
level.
O ne cannot learn any program m ing technique without practicing it.
T here are several program m ing systems th at can be used for class exercise.
For in stitu tio n s where no such system is available, the A ppendix contains
the description and listing of a simple Pascal-S based concurrent program
ming system that 1 have used for class exercise.

ACKNOWLEDGEMENTS

I am grateful to A m iram Yehudai for th e many discussions that wc have had


over the past few years on program m ing and how to teach it. He was also
kind enough to read the en tire m anuscript and suggest im provem ents.
I
should also like to (hunk A m ir Pnueli for teaching me program m ing
logic and verification, and H enry H irschberg of P rentice/H al) International
for his encouragem ent during the transition from notes to book.
A lso, special thanks to my wife M argalit for drawing the sketches on
which th e illustrations were based.

tv

WHAT IS CONCURRENT
PROGRAMMING?

1.1

FR O M S E Q U E N T IA L T O C O N C U R R E N T P R O G R A M M IN G

Figure l . l shows a n interchange sort program . The program c a n b e c o m


piled into a set of machine language instructions and (hen excculed on a
com puter. The program is sequential; for any given input (of 4 0 integers) the
com puter will always execulc the same sequence o f machine instructions.
If we suspcct that there is a bug in the program then we can debug by
tracing (listing the sequence of instructions executed) or by breakpoints and
snapshots (suspending the execution o f (he program to list the values of the
variables).
T here are b etter sequential sorting algorithm s (see A ho etal., 1974) but
we are going to im prove the perform ance o f this algorithm by exploiting the
possibility o f executing portions o f the sort in parallel. Suppose that (for
n= 10) the input sequence is: 4, 2, 7 , 6 , 1, 8, 5, 0, 3, 9. Divide the array into
two hatves: 4 ,2 ,7 ,6 , I and 8, 5 ,0 ,3 ,9 ; get two colleagues to so rt the halves
simultaneously: I, 2, 4, 6, 7 and 0, 3, 5, 8, 9; and finally, with a brief
inspection of the d ata, m erge the tw o halves:
0
0. 1

0. I, 2
A simple complexity analysis will now show ihat even w ithout help of
colleagues, the parallel algorithm can still be more efficient th an the sequen
tial algorithm . In the inner loop o f an interchange sort, there arc (n-~ l ) +
( n - 2 ) + . . . + ! ( / - 1)/2 com parisons. This is approx. n 3/ 2. To sort n /2

CHAP. I

WHAT IS CONCURRENT PROGRAMMING?

program sortprogram ;
const n = 40;
var a: array[ 1..n] of integer;
k: integer,
procedure sort(low,high: integer);
var
i,j, tem p; integer;
begin
for i:= low to high - 1 do
for j := i +1 to high do
if a[j] < a[i] then
begin
tem p := a[j];
a [j]:= a [i]
a [ j ] := te m p
end
end;
begin {* m ain program *}
for k
:=1 to n do read (a[k]);
sort (1,n );
for k: = 1 to n do write (a[k])
end.
F ig. l . l .

elem ents, however, requires only ( n /2 ) 2/2 = n 2/ S com parisons. Thus the
parallel algorithm can perform the entire sort in twice n2/ 8 = n2/ 4 com pari
sons to sort the two halves plus another n com parisons to m erge. The table in
Fig. 1.2 dem onstrates th e superiority o f the new algorithm . T he last column
shows th at additional savings can be achieved if the two sorts arc perform ed
simultaneously.
n
40
100
1000

n 2/ 2

(n2/ 4 ) + n

(n 2 /8)+ n

800
5000
S00 000

440
2600
251 000

140
1350
126 000

Fig. 1.2.

Figure 1.3 is a sequential program for this algorithm . It can be executed


on any com puter with a Pascal com piler and it can be easily translated into
other com puter languages.

SECT- I i

f r o m s e q u e n t ia l t o c o n c u r r e n t p r o g r a m m in g

program sortprogram ,
const n = 20;
twon = 40;
var a: array[1..twon] of integer;
k: integer,
procedure sort{low , high: integer);
(* as before *)
procedure m erge(low, m iddle, high: integer);
var co u n t1, co u n t2 . integer;
k , in d ex1, index 2: integer;
begin
c o u n t1 := low ,
count2 := m id d le;
while count 1 < m iddle do
if a[count1] < a[count2] then
begin
write (a[count1]);
count1 : = c o u n t 1+ 1;
if c o u n t1 > = m iddle t hen
for index2 : = count2 to high do
write(a[index2])
end
else
begin
write (a [ c o u n t2 ] );
count2 : = count2 + 1;
if count2 > high then
begin
for index1 : = c o u n t1 to m id d le- 1 do
write
c o u n t 1 : = m iddle (* terminate *)
end
end
end;
begin (* m ain program *)
for k := 1 to tw on do read (a[k]);
sort( l , n);
so rt(n + 1, tw o n );
m erge(1, n + 1 , tw on)
end.
F l* . 1.3.

W IIA r IS CONCURRENT PROGRAMMING?

CHAR I

Suppose that the program is lo b e run on a multiprocessor com putera


com puter with more than one CPU. T hen we need some notation (hut can
express the fact that the callssori[ 1,/) anilxor/(n + 1, tw on) can be executed
in parallel. Such a notation is the cobcgin -coend bracket show n in Fig. 1.4.
cobcgin p x\ . . . ; p coend means: suspend the execution of the main prog*
ram ; initiate (he execution o f p rocedures............. on multiple com puters;
when all o f
p have term inated then resume live main program.
program sortprogram;
( declarations as before )
begin ( m ain program )
for k := to iw on d o reaJ(aifc));
cobcgin
so rt(\, n);
so n (n f 1 , tw on)
cocnd;
merge( 1, f 1, twon)
end.
F ig. 1.4.

The program s o f Figs. 1.3 and 1.4 a re identical ex cep t for the
cobegin-cotnd in Fig. 1.4. T here would be no need for both versions if the
definition o f cobegin-cocnd was modified. Instead o f requiring th at the
procedures be executed in parallel, cobegin-coend becom es a declaration
that the procedures m ay be executed in parallel. It is left to the im plem enta
tionthe system hardw are and softw are to decide if parallel execution will
be done. Processors may be added o r rem oved from the system without
affecting the correctness of the program only the tim e th at it would take to
cxccuic iIk; program.
T he word concurrent is used to describe processes that have the poten
tial for parallel execution. We have shown how an algorithm can be
im proved by identifying procedures th at may be executed concurrently.
While the greatest im provem ent is obtained only under true parallel execu
tion. it is possible to ignore this im plem entation detail w ithout affecting the
superiority o f the concurrent algorithm o v er the sequential algorithm,
1 .2

C O N C U R R E N T P R O G R A M M IN G

C oncurrent program m ing is the name given to program m ing notations and
techniques for expressing potential parallelism and for solving the resulting
synchronization and com m unication problem s. Im plem entation o f parallel
ism is a topic in com puter systems (hardw are and softw are) th at is essentially

SCC I. 1.2

CONCURRENT PROGRAMMING

independent of concurrent program m ing. C oncurrent program m ing is


important because it provides an abstract setting in which lo study parallel
ism without getting bogged down in the im plem entation details. This abstraction has proved to be so useful in writing clear, correct software that
modern program m ing languages offer facilities for concurrent program
ming.
The basic problem in writing a concurrcni program is to identify which
activities may be done concurrently. If the merge procedure is also included
in the cobcgin-coend bracket (Fig. 1.5), the program is no longer correct. If
you m erge the data in parallel with sorting done by your tw o colleagues, the
scenario o f Fig. 1.6 might occur.
cobegin
so r i(I, rt);
so n (n + 1, iw on);
merge( 1, + 1, frvoti)
cocnd
F if. 1.5.

Initially
Colleague 1 cxcltangcs
Collcaguc2 cxchangcs
You merge
You merge
You merge

C olleague)

Coltcague2

You

4 . 2. 7. 6 . 1

8. 5, 0, 3, 9
8, 5, 0, 3. 9
5. 8. 0, 3. 9

_
-

2. 4, 7, 6 , 1
2. 4, 7, 6. 1

,,

..

2
2 .4
2. 4. 5

F ig. 1.4.

However, merge could be a concurrcni process if there were some way


of synchronizing its execution with the execution o f tlte sort processes
(Fig. 1.7).
while countl < m iddle do
wait until i o f procedure call s o r t(l,n ) is greater than co u n tl and i o f
procedure call sort(n + I . tw on) is greater than count2 and only then:
if a[conntf] < a[count2J then

K g . 1.7.

Parallelism is im portant not only for the im provem ent that can be
achieved in program perform ance but also in program quality. C onsider the

W IIA T IS C O NCURRENT PRO C RAM M ING ?

CHAP. I

follow ing problem :


R ead 80-colunui card s and p rint th em o n ! 2 5 -ch aracier lines. However,
every run o f = 1 to 9 blan k spaces is lo be rep laced by a single blank
follow ed by the n u m eral n.
T his pro g ram is difficult to w rite as a seq u en tial p ro g ram . T h ere are
m any in teractin g special cases: a ru n of b lan k s o v erlap p in g th e en d o f a card,
the p air blank* o v erlap p in g th e e n d o f a line an d so on. O n e way to im prove
the clarity o f the pro g ram w ould be lo w rite th re e se p a ra te program s: one to
re a d c a rd s an d w rite a stream o f ch arac te rs o n to a te m p o rary file; a second
pro g ram to read this c h a ra cte r stream an d m odify ru n s o f blanks, w riting the
new stream o n to a seco n d tem p o rary file; an d a th ird p ro g ram to re a d the
second tem p o rary file and p rint lines o f 125 c h a ra c te rs each.
T his so lu tio n is n o t accep tab le because of the high o v e rh e a d o f the
tem p o rary files. H ow ever, if the th ree p ro g ram s could be run concurrently
(n o t necessarily in p arallel) a n d com m unications p ath s co u ld be established
b etw een th em , th e n the p rogram s w ould be b o th efficient an d elegant.
Sequence
of
INPUT

* ----------

" ----------

**........
OUTPUT

cards

Processes P | ,

1 .3

may execute concurrenlly

CO RRECTNESS OF C O N C U R R E N T PR O G R A M S

C o n cu rren t pro g ram m in g is m uch m ore difficult th an seq u en tial p ro g ra m


m ing because of the difficulty o f e n su rin g th at a co n c u rre n t p ro g ram is
co rrect. C o n sid er the seq u en tial so rt p ro g ram s o f Figs. 1.1 a n d 1.3: if they
w ere tested on several sets o f input d ata th en we w ould feel confident that
they a re co rrect. G u id elin es for testing w ould be to include a so rted in p u t, a
rev ersed input, an input all o f w hose elem en ts a re identical and so on. A
run-of-the-m ill b u g (such as an incorrect fo r-lo o p lim it) w ould seldom
escape d ete c tio n .
T h e scenario in Fig. 1.6. illustrates th a t th e co n c u rre n t p ro g ram o f Fig.
1.5 is inco rrect. H o w ev er, th is program is not a seq u en tial pro g ram and
o th e r scenarios exist. If the pro cesso rs assigned to so rt are sufficiently rapid
then m erge may alw ays be w orking o n so rted d a ta . In th a t case, n o a m o u n t'o f
testing w ould d ete c t any p ro b lem . O n e day (p e rh a p s m o n th s a fte r the
program has b een p u t in to p ro d u ctio n ) an im p ro v ed c o m p o n e n t in th e
co m p u ter system causes the m erge to speed u p and th e n th e pro g ram gives
incorrcct answ ers as d e m o n stra te d in 1.6. O f co u rse the n a tu ral reactio n is:

1.4

IN TE R LE A V IN G

w T his program w orked y esterd ay so th e new co m p o n en t m ust be a t fau lt."


|> A scenario is a d e scrip tio n o f a possible execution seq u en ce of a prom and show s how a c o m p u te r m ight act o u t a pro g ram . It is usually
d lo sh o w that a pro g ram is in co rrect: since th e c o m p u te r may cxccutc the
^fo g ram in a m an n er th a t p ro d u ces th e w rong an sw er, the pro g ram cannot
corrcci.
.
C onversely, how can we show th a t th e co n cu rren t pro g ram in Fig. 1.4 is
COrrccl? It no longer m ak es sen se to look fo r an d test p a th s th a t can be
execution scqucnccs. A t tim es, th e re may be tw o such seq u en ces caused by
parallel execution o f the alg o rith m .
Sequential pro g ram m in g has a w ell-developed p ro o f th e o ry . A ssertions
| are made about the sta te o f the c o m p u ter (i.e. the values o f th e v ariables and
j lhc program c o u n te r) b efo re an d a fte r ex ecu tin g an in stru c tio n , and these
are th en com bined in to a logical p roof. In co n c u rre n t p rogram m ing, this
' m ethod needs to be m odified becau se th e p ro g ram s can in te rfe re with each
other.
T he correctness assertio n s fo r p ro c e d u res sort and m erge o f the previ
ous sections are ele m e n ta ry to state a n d prove:
sort input assertio n : a is an array o f integers,
sort o u tp u t assertio n : a is so rte d , i.e. a now c o n tain s a p erm u ta tio n of
the original e lem e n ts a n d they are in ascending o rd e r,
m erge input assertio n : the tw o halves o f a arc so rte d " .
m erge o u tp u t assertio n : th e e le m e n ts o f a have b een w ritten in ascend
ing o rd er.
T he correctness o f the pro g ram in Fig. 1.1. is im m ed iate from the
correctness o f p ro ced u re sort. T he c o rrectn ess o f 1.3 is easily o b tain ed by
concatenating the co rre c tn ess p ro o fs o f sort a n d m erge. T h e co rrectn ess of
Fig. 1.4 needs a new te ch n iq u e. W e have to be able to e x p ress th e fact that
the two instances o f sort d o n o t in te rfe re w ith o n e a n o th e r. T h e program in
Fig. 1.5 is incorrect th o u g h th e p ro ce d u res com prising it are co rrec t; u n fo r
tunately, they in teract in a m an n e r which m akes th e p ro g ram incorrect. The
program in 1.7 is c o rrec t bu t new ideas are n e ed ed to be able to reason abo u l
synchronization.

1 .4

IN T E R L E A V IN G

Interleaving is a logical device th a t m ak es it possible to analyze the co rrect


ness o f co n c u rre n t pro g ram s. Suppose th a t a co n c u rre n t p ro g ram P co n sists
of tw o p rocesses /*, an d P2. T h e n we say th a t P cx ccu tcs any o n e o f the
execution seq u en ces th a t can be o b ta in e d by in terleav in g th e cxccution
scqucnccs o f th e tw o processes. It is a s if som e su p ern a tu ra l being w ere lo
execute th e instru ctio n s one at a tim e, each tim e flipping a coin to dccidc
w h eth er th e next in stru ctio n will be from P , o r P2.

W HAT IS CONOURRLN1 PROGRAMMING?

CHAP 1

We claim ihat these execution sequences exhaust the possible behaviors


of P. C onsider any instructions /, and l } from Pt and P2, respectively. I f /, and
/j do not access the sam e m em o ry ccJI o r register th en it certainly does not
m atter if /, is executed before / f, a f te r /j or even sim ultaneously w iih /j (if the
haidw are so allows). Suppose on the o th er hand that 1, is "S tore 1 into
memory cell M" and that l t is Store 2 into m em ory cell M '\ If /, and / 2 are
executed sim ultaneously then the only reasonable assum ption is that the
result is consistent. T hat is, cell M will contain either 1 o r 2 and the com puter
docs not store an o th er value (such as 3) of its own volition.
if this were not true then it would be im possible to reason about
concurrent programs. The result of an individual instruction on any given
data cannot depend upon the circum stances of its execution. Only the
external behavior of the system may changed epending upon the intcrac*
tion of the instructions through the com m on d ata. In fact, com puter
hardw are is built so that the result of executing an individual instruction is
consistent in the way just defined.
I l i u s j t i h c result o f the sim ultaneous execution o f / , and is ) then this
is the same as saying that /, occurred before / 2 in an interleaving and
conversely if the result is 2.
Interleaving docs not m ake the analysis of concurrent program s simple.
T he num ber of possible execution sequences can be astronom ical. N everthe
less. interleaved execution sequences are am enable lo form al m ethods and
will allow us to dem onstrate the correctness of concurrent programs.
1 .5

THE O R IG IN OF O P E R A TIN G S Y S T E M S

Concurrent program m ing, though generally applicable, grew out of p ro b


lems associated with operating systems. This scction outlines the develop
ment o f such systems so that the background to the grow th of concurrent
program m ing can be appreciated.
It is not often that an obsolete technology reappears. Programmable
pocket calculators have resurrected machine language program m ing: abso
lute addresses must be used for data and labels. On the o ther hand, the
ow ner is not constrained lo working during the hours th at the com puter
center is open.
W hile th e pocket calculator is a marvel o f electronics, m achine language
program m ing directly on the com puter is slow and difficult. In the 1950s,
when com puters were few and expensive, there was great concern over the
waste caused by this m ethod. If you signed up to sit at the com puter console
from 0130 lo 0200 and you spent 25 m inutes looking for a bug, this 25
m inutes o f com puter idle tim e could not be recovered. N or was your
colleague who signed up for 02 0 0 -0 2 3 0 likely to lei you start another run
at 0158.
If we analyze what is happening in the term s of the previous sections we

II

SfcCT I 5

M liim

iiiJ E M

iL iM

a M

T M

I T f r

THIf O R IG IN OF OPfcRA I INC. SYSTEMS

see that (he m anual procedures that must be perform ed m ounting tapes,
selling up card decks, o r changing places at th e consolearc disjoint from
the actual com pulation and can be perform ed concurrently with (he com pu
ter's processing.
T he sccond generation o f com puters used a supervisor program to
butch jobs. A professional com puter o p erato r sat at the console. Program
m ers prepared card decks which were concatenated into batches" that were
fed into the com puter once an hour or so. The increase in throughput (a
m easure o f the efficiency o f a com puter; ii is the num ber of jobssuitably
w eighted thai can be run in a given tim e period) was enorm ousthe jobs
were run one after another with no lost m inutes. The program m ers, how
ever, Inst the ability to dynamically track th e progress of th eir program s since
they no longer sat at the com puter console. In the event of an error in one
job, (he com puter simply com m enced execution o f the next jo b in Hie batch,
leaving the program m er (o puzzle o u t w hat happened from core dumps.
With h turnaround time (the am ount of time that elapses between a job
being subm itted for execution and th e results being printed) of hours or
days, the task of program m ing became more difficult even though certain
aspects were im proved by high-level languages and program libraries.
D espite this im provem ent in throughput .system s designers had noticed
another source o f inefficiency not apparent to the hum an eye. Suppose that a
com puter can cxccute one million instructions p er sccond and that it is
connected to a card reader which can read 300 cards per m inute ( = one card
in 1/5 second). T hen from the time the read instruction is issued until the
time the card has been read , 200 0 0 0 instructions could have b een executed.
A program to read a deck o f cards and print the average of the numbers
punched in the cards will spend over 99 % of its tim e doing nothing even
though 5 cards per sccond seem s very fast.
The firsl solution to (his problem was spooling. The I /O speed o f a
magnetic (ape is much greater th an that o f the card read er and the line
printer that are the interface betw een the com puter and the program m er.
We can decom pose the operation of the com puter into three processes: a
process to read cards to tape; a process lo cxecute the program s on the tape
and wrile the results onto a second tape; and a process to print the inform a
tion from (he second tape. Since these processes are disjoint (cxcept for the
exchange o f the tapes after processing a batch), the throughput can be
greatly increased by running each process on a separate com puter. Since
very simple com puters can be used to transfer inform ation to and from (he
magnetic tape, the increase in cost is not very great com pared lo the savings
achieved by more efficient use of the main com puter.
L ater generations of com puter systems have attacked these problems
by switching the com puter am ong several com putations whose programs
and data are held sim ultaneously in memory. This is known as m ultiprog
ramming. While I / O is in progress for program P, the com puter will execute

"

"

'

10

W HAT IS CONCURRENT PROGRAMMING?

CHAP. 1

several thousand instructions o f program Pt and (hen rclurn to process the


data obtained for Pt. Similarly, while one program m er sitting ai the terminal
o f a lime-sharing system f is thinking, (he com puter will switch itself to
execute the program requested by a second program m er. In fact, modern
com puter systems arc so powerful (hat (hey can switch (hem selves am ong
dozens o r even hundreds o f I/O devices and terminals. Even a m inicom pu
ter can deal with a dozen (erminals.
The im portance o f the concept of interleaved com putations m entioned
in the previous section has its roo(s in these m ultiprogram m ed systems.
R jlh cr than attem pt to deal with (he global behavior o f the switched com pu
ter, we will consider the actual processor to be merely a m eans of interleav
ing the com putations of several processors. Even though m ultiprocessor
system s system s w ith m ore th an one c o m p u ter w orking sim u ltan e
ouslyare becoming more com m on, the interleaved com putation model is
still appropriate.
The sophisticated software systems that are responsible for m ulti
program m ing are called operating systems. The term operating system is
often used 10 cover all m anufacturer-provided software such as I /O p ro
gram s and compilers and not just the software responsible for the m ulti
programming.
While ihe original concern of operating system designers was to
im prove throughput, it soon turned out that the throughput was affected by
num erous system crashes when the system slopped functioning as it was
supposed to and extensive recovery and restart m easures delayed execution
o f jobs. T hese defects in the operating systems were caused by our inadequ
ate understanding of how to execute several program s sim ultaneously and
new design and program m ing techniques are needed to prevent them .

1 .6

O PE R A TIN G S Y S T E M S A N D C O N C U R R E N T P R O G R A M M IN G

If you could sense the operation of a com puter thai is switching itself every
few milliseconds am ong dozens o f tasks you would certainly agree that the
com puter seem s to be perform ing these tasks sim ultaneously even though
we know that the com puter is interleaving the com putations of the various
tasks. I now argue th at it is m ore than a useful fiction lo assum e that the
com puter is in faci perform ing its tasks concurrently. To see why this is so, let
us consider task switching in greater detail. Most com puters use interrupts
t A tim e-sharing system is a com p uter system th at allows many program m ers to
work sim ultaneously at teim inats. E ach program m er m ay w ork under the
illusion (hat ihe co m p u ter is w orking for him alone (though Ihe co m p u ter may
seem lo be w orking slowly if loo m any term inals are connccted).

SECT I 6

OPhKATlNCl SYSTEMS ANO CONCURRENT PROGRAMMING

II

for this purpose. A typical scenario for task switch by interrupts is as follows.
Program
m akes a read request and then has its execution suspended. 11k
CPU may now cxccute program Pt . W hen th e read requested by P, has been
com pleted, the I /O device will interrupt the execution of Pt to allow the
operating system to rccord the com pletion o f the read. Now the execution of
cither P, or Pt may be resum ed.
The interrupts occur asynchronously during the execution of programs
by the C PU . Oy this is m eant that ihere is no way o f predicting o r coordinat
ing the occurence of the interru p t with the execution o f any arbitrary
instruction by the CPU. For exam ple, if the o p erato r who is m ounting a
magnetic tape happens to sneeze, it may delay the tape read y " signal by
8.254387 seconds. I low cvcr, if he is slow" with his handkerchief, the delay
might be 8.254709 seconds. Insignificant as that difference may seem, it is
sufficient for the CPU lo execute dozens of instructions. T hus for all practi
cal purposes it m akes no sense lo ask: W hat is the program that the
com puter is executing?" The com puter isexecuting any one o f a vast number
of execution sequences that may be obtained by arbitrarily interleaving the
execution of the instructions of a num ber of com puter program s and I/O
device handlers.
This reasoning justifies the abstraction th at an operating system consists
of many processes executing concurrently. The use o f the term process
rather than program em phasizes tin; fact that we need not differentiate
betw een ordinary program s and external devices such as term inals. They are
all independent processes that may, how ever, need to com m unicate with
each other.
T he abstraction will try to ignore as many details of the actual applica
tion as possible. For exam ple, we will study the p roduccr-consum er problem
which is an abstraction both of a program producing d ata for consum ption by
a printer and of a card reader producing data for consum ption by a program.
The synchronization and com m unication requirem ents are the same for
both problem s even though the details of program m ing an input routine are
rather different from the details o f an o utput routine. Even as new I/O
devices are invented, the input and output routines can be designed within
the fram ew ork of the general producer-eonsum er problem .
O n Ihe other hand, we assume th at each process is a sequential process.
It is always possible to refine the description of a system until it is given in
term s o f sequential processes.
The concurrent program m ing paradigm is applicable to a wide range of
systems, not just to the large m ultiprogram m ing operating systems that gave
rise to this viewpoint. M oreover, every com puter (except perhaps a cal
culator or the simplest m icrocom puter) is executing progam s that can be
considered to be interleaved concurrent processes. M inicom puters are sup
plied with small m ultiprogram m ing systems. If not, (hey may em bedded in

12

WHAT IS CONCURRENT PROGRAM MING?

CHAP. I

real-time systems* where (hey are cxpcctcd to concurrently absorb and


process dozens o f different asynchronous external signals and operator
commands. Finally, netw orks of interconnected com puters are becoming
common. In this case true parallel processing is occurring. A nother term
used is distributed processing to em phasize that the connected computers
may be physically separated. While the abstract concurrency that models
switched systems is now well understood, the behavior o f distributed systems
is an area of current research.
1.7

A N O V E R V IE W OF TH E BOOK

Within the overall context of writing correct software this book treats the
single, but extrem ely im portant, technical point of synchronization and
communication in concurrent program m ing. T he problem s are very subtle;
ignoring the details can give rise to spectacular bugs. In C hapter 2 we shall
define the concurrent programming abstraction and the argum ents that
justify each point in the definition. The abstraction is sufficiently general
that it can be applied w ithout difficulty to real systems. O n the o ther hand it
is sufficiently sim ple lo allow a precise specification of both good and bad
behavior o f these program s.
Form al logics exisl which can form ulate specifications and prove prop
erties o f concurrent program s in this abstraction though we will limit o u r
selves to informal o r at most semi-formal discussions. The fact th at the
discussion is inform al must not be construed as m eaning th at the discussion is
imprecise. A m athem atical argum ent is considered to be precise even if it is
not formalized in logic and set theory.
The basic concurrent program m ing problem is that o f m utual exclusion.
Several processes com pete for the use o f a certain resource such as a tape
drive but the nature of the resource requires that only one process at a time
actually accessed the resource. In o th er words, the use of the resource by one
process excludes o th e r processes from using the resource. C hapter 3 pre
sents a scries of attem pts to solve this problem culm inating in the solution
known as P c k k e r's algorithm . The unsuccessful attem pts will each point out
a possible "b a d behavior of a concurrent program and will highlight the
differences betw een concurrcnt and sequential programs.
D ekkcrs algorithm is itself too complex to serve as a model for more
complex program s. Instead, synchronization primitives are introduced. Just
as a disk Tile can be copied o n to tape by a single control language com m and
t W hciircas a lim e-sharing system gives the usei live ability to use all (he
resources o f a com puter, the term real-tim e system is usually restricted to
system s th at arc required to respond to specific pre-dcfincd requests from a
user o r an external sensor. Exam ples w ould be air-traffic control system s and
hospital m onitoring systems.

M A T. 1.7

AN OVERVIEW O f - T ill: BOOK

13

or a file can be read by writing read in a high level language, so we can define
programming language constructs for synchronization by th eir semantic
definitionwhat they are supposed lo d o and not by their im plem enta
tion. Wo shall indicate in general term s how these primitives can be
im plem ented but the detail* vary so much from system to system that to fully
describe them w ould defeat our purpose o f studying an abstraction. H ope
fully. it should be possible for a ''casu al systems program m er to write
concurrcni program s w ithout knowing how the prim itives arc implemented.
A model im plem entation is described in the Appendix.
C hapter 4 com m ences the study of high level prim itives with E. W.
D ijkstras sem aphore. T he sem aphore has proved extraordinarily successful
as the basic synchronization primitive in term s of which all others can be
defined. The sem aphore has bccomc the standard of com parison. It is
sufficiently powerful that interesting problem s have elegant solutions by
sem aphores and it is sufficiently elem entary that it can be successfully
studied by formal m ethods. T he chaptcr is based on the producer-consum er
problem m entioned above; the mutual exclusion problem can be trivially
solved by sem aphores.
Most operating systems have been based on monolithic monitors. A
central executive, supervisor o r kernel program is given sole authority over
synchronization. M onitors, a generalization o f this conccpt formalized by
H oarc, arc the subject o f C hapter S. T he m onitor is a powerful conccptua!
nolion that aids in the developm ent of well structured, reliable programs.
The problem studied in this chapter is the problem o f the readers and the
writers. This is a variant of the m utual exclusion problem in which there arc
two classes of processes: w riters which need exclusive access to a resource
and readers which need not exclude one another (though as a class they must
exclude all writers).
The advent of distributed systems has posed new problem s for concur
rent program m ing. C. A. R. Ilo arc has proposed a m ethod of synchroniza
tion by com m unication (also known as synchronization by rendezvous)
appropriate for this type of system. T he designers o f the Ada programming
language have chosen to incorporate in the language a variant of H oares
system. A nticipating the future im portance of the A da language. C hapter 6
studies the A da rendezvous.
A classic problem in concurrent program m ing is (hat of the Dining
Philosophers. T hough the problem is o f g reater entertainm ent value than
practical value, it is sufficiently difficult to afford a vehicle for the com pari
son o f synchronization primitives and a standing challenge to proposers of
new systems. C hapter 7 reviews the various primitives studied by examining
solutions to the problem of (he Dining Philosophers.
Program m ing canno( be learned w ithout practice and concurrent pro
gram ming is no exception. If you are fortunate enough to have easy access to

14 WHAT IS CONCURRENT PROGRAMMING?

ClIAP. I

a m inicom puter or to a sophisticated simulation program , there may be no


difficulty in practicing these new concepts. If not, th e A ppendix dcscribcs in
full detail an extremely simple sim ulator of concurrency that can be used for
class cxcrcisc. In any case, the A ppendix can serve as an introduction to
im plem entation of concurrency.
The book ends with an annotated bibliography suggesting further study
o f concurrent programming.
1 .8

PR O C R A M N O T A TIO N

The exam ples in the text will be w ritten in a restricted subset o f Pascal*
S, which is itself a highly restricted subset of Pascal. T his subset must of
course be augm ented by constructs for concurrent programming. It is
intended th at the exam ples be legible to any program m er with experience in
Pascal, A da, C, A lgol, o r P L /I.
The im plem entation kit in the A ppendix describes an interpreter for
this language that will execute the exam ples and that can be used to program
the exercises. The language in the kit contains m ore Pascal language features
than arc used in th e text o f the book and thus users of the kit are assumed to
be able to program in sequential Pascal. These extra features are necessary
in o rd er to use the kit to solve the exercises, although the exercises them
selves could be program m ed in o th er languages th at provide facilities for
concurrent programming.
The exam ples in the chapter on m onitors are standard and can be
adapted to the m any systems that provide the m onitor facility such as
C oncurrent Pascal, Pascal-Plus, or C S P /k. The exam ples in the chapter on
the A da rendezvous are executable in A da.
We now present a sketch of the language that should be sufficient to
enable program m ers unfam iliar with PasCHl to understand the examples.
1. C om m ents are inserted betw een ( and ).
2. The first line in a program should be
program name;
3. Symbolic nam es for constants may be declared by the word const
followed by the constant itself:
const rw'O/i*40;
4. All variables in each procedure in the main program must be declared
by the word v ar followed by the nam es o f the variables and a type:
var i, j, temp: integer,
fo u n d : boolean;

SECT. I $

PROGRAM N O IA IIO N

IS

The available types are : integer, boolean (with constants true and false)
and arrays:
var a:rr%y{lo\vindex...highindex] of integer;
5. Following tltc declaration of the variables, procedures and functions
may be declared: procedure nam e ( fo rm a l parameters ); and func*
lion nam e ( fo rm a l parameters ): retu rn typ e,. The formal param e
ter definition has the same form as that of a variable list:
procedure sort (low .high: integer)-,
function lust(index: integer): boolean)
6. The body of the main program o r of procedures is a sequence of
statem ents separated by sem i-cotons betw een begin and end. The main
program body is term inated by a period and the procedure bodies by
sem icolons. T he usual rules on nested scopes apply.
7. The statem ents are:
assignment statement
If boolean -expression then statement
if boolean-expression then statement else statement
for index-variable : = low index to highindex do statement
while boolean-expression do statement
repeat sequence-of-statements until boolean-expression
The syntactic difference betw een while and repeat is that while takes a
single statem ent and repeat takes a sequence of statem ents (separated
by semi-colons). The sem antic diffcrcnce is th at the while lests before
the loop is done and repeat tests afterw ards. Thus repeat executes its
loop at least once.
8. A sequence of statem ents may be substituted for siatem cn t" in the
above forms by enclosing the sequence of statem ents in the bracket
begin ... end to form a single com pound statem ent:
if c\j] < a{t] then
begin
tem p := a(/'];
a[j] : a[i];
[i] := temp
end
In detail this is read: If the boolean expression (c[j) < *[]) has the value
true, then cxccute the com pound statem ent which is a sequence of
three assignm ent statem ents. If the expression is false, then the (com
pound) statem ent is not executed and the execution continues with the
next statem ent.

16

W H A T IS CONCURRENT PR O G R AM M IN G

C HA P I

9. A ssignm ent statem en ts a rc w ritten v ariab le : expression. T h e v ari


able m ay be a sim ple variable o r an ele m e n t o f an array : 0( 1']. T h e type
(integer o t boolean) o f the ex pression m ust m atch th a t o f (he variable.
In teg er expressions arc co m p o sed o f in teg er v ariables and co n stan ts
using the o p erato rs: + ,
, div (in teg er divide w ith tru n c a tio n ) and
mod B oolean ex p ressio n s m ay be fo rm ed from relatio n s b etw een
integer expressions: = , < > (n o t e q u a l), < , > , < = (less th an o r e q u a l)
> = (g rea ter th an o r e q u al). T h e bo o lean o p e ra to rs an d . o r an d not
may be used to form c o m po u nd bo o lean expressions.
10. F o r those w ho know Pascal we list h ere th e a d d itio n al featu res th at are
d efin ed in the language o f the im p lem en tatio n kit som e o f w hich will
be necessary if you plan to w rite any p ro g ram s using th e kit.
(a ) T y p e d ecla ratio n s. Since th e re arc no scalar, sub ran g e o r reco rd
types, this is m ostly useful fo r a rray types:
type sortarray = a rr a y [l..n ] o f integer
v a r a: sortarray,
(b ) C h a ra c te r co n stan ts and v ariables o f type ch ar.
(c ) M ultidim ensional array s (array s o f array s).
(d ) A p a ra m e te r m ay be passed by refe re n c e ra th e r th an value by
prefixing th e form al p a ra m e te r by var.
(e ) R ecursive functions a n d p rocedures.
(f) I / O m ay be p erfo rm ed o nly on th e sta n d a rd textfiles in p u t and
o u tp u t. T o en su re th a t y o u d o n o t forget this restrictio n , the
d e c la ra tio n o f e x te rn a l files in th e p ro g ra m c a rd h a s b e e n
rem o v ed , read, readln, write, w riteln, eo ln , e o f (all w ith o u t a file
p a ra m e te r) function a s in Pascal. O n ly the d efau lt field w idths may
be used in a write, w hich will, how ever, accep t a strin g as a field to
be p rin ted :
writeln { the answ er i s , n).

1 .9 E X E R C tS E S t
1.1

Wiite a two-process concurrent program to find the mcun of n numbers.

1.2

Write a thiee-process concurrcni program to multiply 3 x 3 matrices.

1.3

Each process of the matrix multiply program executes three multiplications


and two additions for each of three rows or altogether IS instructions. How
many execution sequences of the concurrent program may be obtained by
interleaving the executions of the three processes?

t S lig h tly h a rd e r exercises are m a rk e d th ro u g h o u t the b o o k w ith an asterisk (* ).

#
EXERCISES

1.4

17

Perform a similar analysis (or sonprogram. You will have to make some
assumptions on Ihe number of interchanges lhat will be done.

1.5 Test the concurrent sonprogram of Fig 1.3.


1.6 Test the concurrent sonprogram of Fig. 1.4 which has the merge defined as a
third process. Run the program several times with exactly the same data.
1.7

Run the program in Fig. 1.8 several times. Can you explain the results?
program increment',
const m 20;
var n: integer;
procedure incr;
var i: integer,
begin
for i :* 1 lo m do n : n+ 1
end;
bgin ( main program )
n : * 0;
cobegin
incr; incr
cuend;
writeln (' ihe sum is n)
end.
Pig. 1.8.

2 .1

THE CONCURRENT
PROGRAMMING ABSTRACTION

IN T R O D U C T IO N

C oncurrent program m ing is not the study of operating systems or real-time


systems, but of abstract program m ing problem s posed under ccrtain rules.
C oncurrent program m ing was m otivated by the problem s of constructing
operating systems, and its exam ples are abstract versions of such problem s.
Most im portantly, the rules of concurrent program m ing are satisfied in many
systems and thus its tcchniqucs can be used in real systems. C om ponents o f a
system which arc not am enable to concurrent program m ing techniques
siiouid be singled out for extrem ely carcful design and im plem entation.
C hapter I gave the definition of a concurrent program . It consists of
several sequential processes whose execution sequences are interleaved.
T he sequential program s arc not totally independent - if they were so there
would be nothing to study. T hey must com m unicate with each o th er in order
to synchronize o r to exchange data.
T he first m eans of com m unication that we shall study is the com m on
m em ory. T his is appropriate for the pseudo-parallel switched com puters
where all processes are running on the same processor and using th e same
physical m em ory. It is also used on som e truly parallel systems such as the
C D C C y b er co m p u ters w here even though one C PU and ten PP 's
(peripheral processors) arc sim ultaneously executing separate program s,
synchronization is accomplished by having the PPs read and w rite the
C PU s mem ory. In o ur abstraction, com m on m em ory will be represented
simply by global variables accessible to all processes.
C om m on m em ory can also be used to hold access-restricted proce
dures. Access to these procedures is, in cffcct, allocated to a process. T his is
the way most third generation operating systems were im plem ented. The
system' programs can only be called by special instructions which ensure
that only one process at a tim e is executing a system program .
I8

SECT. 2.2

M U TU AL EXCLUSION

19

W ith the introduction o f distributed com puting it is no longer valid to


assume that a comm on central mem ory exists. C hapter 5 discusses concur*
rent program m ing by means of sending and receiving signals instead of
reading and writing a comm on variable o r executing a com m on procedure.
Synchronization by message-passing has been used on several experimental
systems for singlc-processor com puters but this approach has not been
widely accepted because o f the possible inefficiency o f message-passing
compared with sim pler systems. O f course, distributed systems have no
choice.

2 .2

M U T U A L E X C L U S IO N

Mutual exclusion is one of the two most im portant problem s in concurrent


programming because it is the abstraction of many synchronization pro b
lems. We say that activity A , o f process P x and activity A 2 of process P2 must
exdudc each o th er if the execution of A x may not overlap the execution o f
A j. If Px and Pt simultaneously attem pt to execute their respective activities,
A then we must ensure that only o ne of them succeeds. The losing process
must block; that is. it must not proceed until the winning process completes
the execution of its activity A .
The most com m on example o f the need for m utual exclusion in real
systems is resource allocation. Obviously, two tapes cannot be mounted
simultaneously on the sam e tape drive. Some provision must be m ade for
deciding which process will be allocated a free drive and some provision
must be m ade to block processes which request a drive when none is free.
There is an obvious solution: run only one jo b at a tim e. But this defeats one
of the main aims o f concurrent program m ing - parallel execution of several
processes.
Meaningful concurrency is possible only if the processes are loosely
connected. T he loose connection will manifest itself by the need for short
and occasional com m unication, T he abstract m utual exclusion problem will
be expressed:
remainder
pre-protocol
critical section
post-protocol.
remainder will be assum ed to represent some significant processing.
Occasionally, i.e. after the com pletion o f remainder, the process needs to
enter a short critical section. It will execute certain sequences o f instructions,

20

I Mfc CONCURRhNT PROGRAMMING ABSTRACTION

CHAP. 2

tailed protocols before and possibly after (he critical section. These pro
to c o l will ensure that (he critical section is in fact executed so as to exclude
all other critical sccitons. O f course, just as (he critical section should be
short relative to the main program in order to benefit from concurrency, (he
protocols must also be relatively short. The protocols represent the over*
head paid for concurrency. Hopefully, if the critical sections and the pro*
tocols are sufficiently short (hen the significant processing abstracted as
remainder can he overlapped (hus justifying (he design o f the multipro
gramming system.
There is another, more im portant, reason for requiring loose connec
tion am ong concurrent processes and that is to ensure reliability. We want to
be assured (hat if ihere is a hug in one o f (he processes, then i( will not
propagate itself into a system "crash . It should also be possible 10 gracefully
degrade the perform ance of a system if an isolated device should fail ("fail*
soft ). It would be absurd to have a system crash just because one tape drive
becam e faulty.
T he abstract requirem ent will be that, if a process abnorm ally term i
nates outside the critical section then no o th er process should be affectcd.
(F o r this purpose the protocols are considered to be p art of the critical
section.) Since the critical section is where the com m unication is taking
place, it is not reasonable to require the same of (he critical sections. We
might use (he following m etaphor. If a runner in a relay race fell after he has
passed the baton then the race should not be affected. It is unreasonable to
hope that the race is unaffected if the fall occurred at the critical moments
during the baton exchange.
This restriction is not unreasonable even in practice. Critical sections
such as disk I/O will often be executed by com m on system routines or by
com piler-supplied routines which have been w ritten by a com petent systems
program m er. T he probability of a softw are e rro r in such a routine should be
much sm aller than in a run-of-the-mill program.
2 .3

CO RRECTNESS

W hat does it m ean for concurrent program s to be correct? A n ordinary


program is correct if it halls and prints the " rig h t" answ er. In general, you
will know a "rig h t answ er if you see one. IT m is also true of some concur
rent program s such as subprogram .
O n the o ih e r hand, the single most distinguishing feature o f an o p e n
ing system o r real-tim e system is that it must never hah. The only way lo hall
a typical o perating system is (o push the start b utton on (he com puter panel.
An operating system prints nothing o f its own (except som e non-essential
logging and accounting d ata). Thus when studying o perating systems, we

.IfcCT. 2.3

CORRECTNESS

21

must revamp o u r notions o f what it m eans fo ra program to be correct. Sincc


, most concurrent program m ing is done within operating systems and real
time systems, this is the area to be studied in this book.
An ob\iou> truism i< that a m program must d o u h a l its specifications
My that it is supposed to do. This is no less true in Ihe case o f concurtcin
rograim though the specifications are radically different from those of
ucntiiil programs. In o ur abstraction, wc shall distinguish two types of
cctncss properties: safety p roperties and liveness properties.
Safely properties are those required by the sialic portions o f the specifilions. 'Flicsc arc often the only requirem ents explicitly specified. Mutual
inclusion is a safety properly: the requirem ent that critical sections exclude
One another is absolute and does not change during the execution of the
program. The safety property of the producer-consum er problem is that the
consumer must consume every piece of d ata produced by th e producer and
th il it must do so in the o rd er in which they w ere produced.
Safety properties are akin to what is known in the theory o f sequential
programs as partial correctness: if the program term inates, the answers must
be correct". Safely p roperties are usually relatively easy to show. They are
explicitly required by the specifications and program s are designed to m eet
these specifications. You can always achieve more safety by giving up some
concurrency and letting m ore segm ents o f the process execute sequentially.
Violation of m utual exclusion is the cause o f most operating system
crashes. Dynamic mem ory allocation is frequently involved: a process may
be convinced that it knows the location of a certain table in memory while in
fact the table has been rem oved and its mem ory allocated to another
process.
At a com puter center known to the A uthor, an unscrupulous pro
grammer m anaged to insert into the system a program th at, on command,
would give his program s the highest priority. H owever, he did not know that
mutual exclusion protocols were required because the scheduling table was
not fixed in mem ory. Thus the execution of his com m and would often write
into some o th er table of the system causing a crash. Since the crash occurred
many m inutes later, the mem ory dum ps gave no clue as to what had hap
pened. A fter several w eeks, the problem was solved by noting the strange
command on the system log. If such an e rro r had been m ade in a regular
systems program it would have been even more difficult to catch.
Live ness, on the o th er hand, deals with dynamic properties. It is akin to
sequential program m ings total correctness: the program term inates and the
answer is correct , In concurrent systems, livcness m eans th at if something
is supposed to happen then eventually it will happen. If a proccss wishes to
enter its critical section then eventually it will d o so. If a p ro du cer produces
data then eventually the consum er will consum e it.

24

1 H I: C O NCURRENT P KO G R AM M IN C A B S IR A C IIO N

CHAP. 2

will respond to th e p ro to co l just th at m uch faster. A sy n ch ro n o u s system can


generally mix only m odules w hose sp eed s arc m ultiples o f each o th e r.
In the ab stractio n , ccrtain assum ptions will be mailc to avoid m eaningless pathologies. Since infinite delay is indistinguishable from a h alt, we will
assum e (globally) th a t, if th ere is at least one p ro ccss read y to ru n , th e n som e
(unspecified) process is allow ed lo run w ithin a finite tim e. W e also assum e
(locally) th at if a proccss is allow ed lo run in its critical section th e n it
will com plete the execution o f the critical section in a finite p erio d o f
time.
On Ihe o th e r h a n d , we allow o u rselv es lo use the ad v ersary ap p ro ach in
checking fo r possible bugs. A co n cu rren t p ro g ram suffers from deadlock if it
is possible to d e v ise a sc en ario for dead lo ck u n d er Ihe sole finiteness a ssu m p
tio n s of th e p rev io u s p arag rap h . If so m eo n e o ffers you a co n cu rren t p ro g
ram , you can tailo r y o u r co u n te rscc n ario specifically to th e given p ro g ram ;
you are an a d v e rsa ry " allow ed to plot against the p ro g ram .

2 .5

IM P L E M E N T IN G P R IM IT IV E IN S T R U C T IO N S

O u r solu tio n s to the m utual exclusion p ro b lem will alw ays ch c a t by m aking
use o f m u tu al exclusion p rovided on a low er level th e hard w are level. Just
as the u ser of a high level language n eed not know how a co m p iler w orks as
long as he is p ro v id ed w ith an accu rate d escrip tio n o f the syntax and
sem antics o f the lan g u ag e, so we will no t co n cern o urselves w ith how the
hard w are is im p lem en ted as long a s we a re supplied w ith an accurate
descrip tio n o f the syntax an d sem antics o f the arch itectu re. Presum ably the
sam e thing h ap p en s a t low er levels th e c o m p u te r logic d esig n er need not
know exactly how an in te g ra te d circuit is im p le m e n te d ; the in teg rated circuit
desig n er need only co n ccrn him self w ith ihe elec tro n ic p ro p e rtie s o f sem i
co n d u cto rs an d n e e d not know all Ihe d etails o f the q u a n tu m physics th at
explain th ese p ro p ertie s.
In com m on m em ory system s th ere is an arbiter w hich p ro v id es for
m utual exclusion in th e access lo an individual m em ory w ord. T h e w ord
access is a g en eric term fo r read and w rite o r, as they a rc usually called.
L oad and S tore co rresp o n d in g to the a ssem b ler in stru ctio n s for these
actions. T he a rb ite r e n su res th at in case o f o v erlap am ong accesses, m utual
exclusion is o b ta in e d by ex ecu tin g th e acccsscs o n e a fter the o th er. T h e
o rd e r o f the acccsscs is n o t g u ara n te ed to the p ro g ram m er. O n th e o th er
hand, the consistency o f th e access is e n su re d as d escrib ed in C h a p te r 1.
N ote th at the access to a single w ord is a n action th a t m ay not be
a p p aren t in a high level language. Suppose th at n is a global v ariable th a t is
initially zero an d is used a s a c o u n te r by several p ro cesses executing the

S fctT. I 5

IM P L tM liN 'l IN C P R lM lllV h IN S IH U C I IONS

23

instruct ion: n : * + l.T h e com piler com piles such a statem en t into the three
assem bler instructions:
U>ad n
A dd I
Store />
C onsider now the follow ing scen ario . T h e value o f/i is 6. / ', executes L oad/t
jmd then f*3 also ex ecu tes L o u d /i. / , in crem en ts th e v alue o f/i in its interm it
register to o b tain 7. Sim ilarly,
o b ta in s th e v alue 7 in its in tern al register.
Finally, the tw o p ro ccssese x ec u te the S tore in stru ctio n in succession and the
value 7 is sto re d tw icc. H ence the final value o f n is 7. 'Ilia t is wc have
increm ented the value 6 tw ice an d have o b ta in e d 7.
C om m on m em ory a rb ite rs a rc found b o th o n m u ltip ro cesso r systems
am i o n single p ro cesso r system s w hose I / O e q u ip m e n t is c o n n e cte d fo r direct
m em ory access (D M A ). N orm ally a n I / O device w ould tra n sfe r each data
word to th e C P U for th e C P U to sto re in th e m em ory. H o w ev er, th is im poses
an unaccep tab le o v e rh e a d on the C P U . In stead , th e I / O device is given the
address o f a block o f m em ory. It o nly in te rru p ts (he C P U w hen the transfer
of th e w hole block is co m p leted . T h e re is an a rb ite r lo en su re th a t only one
device (o r the C P U ) h as access to ihe m em ory at any o n e tim e.
In this case we say th a l D M A is bein g im p le m e n te d by cycle stealing.
T h e m em ory is assum ed to be driven a t its m axim um access sp eed , say one
access p e r m icrosecond. E ach such access is also called a m em ory cycle. To
im plem ent D M A th e C P U is norm ally allow ed to co m p u te and access
m em ory. W hen a d a ta w ord arrives front an I / O device th e right to access
m em ory is u su rp ed from th e C P U a n d the device is allow ed to " s te a l" a
m em ory cycle. T h e re is no real o v e rh e ad . T h e m em ory cycle is needed
anyw ay to store the w ord an d w ith cycle stealing (h e C P U n eed n o t concern
itself w ith individual w ords.
Ilie co m p u te r h ard w are will be tru ste d to fu n ctio n pro p erly . W c only
concern o u rselv es w ith th e co rre ctn e ss o f the system softw are. T his is not
alw ays tru e o f coursc an d in practice o n e m ust be a le rt (o h a rd w a re malfunclion. O n e o f the m ost speclu cu lar bugs know n to th e A u th o r w as caused by a
hardw are faull that resu lte d in m ixing (wo m em ory ad d re sse s instead of
interleaving them . T h e net result w as a sto re o f d a ta in (he m ixed-up address,
an d (he presence o f foreign d a ta in th e se m em o ry ad d resses was never
explained by softw are specialists. F o rtu n a te ly th is so rt o f th in g rarely hap*
pens.
A n o th e r w ay o f using a co m m o n m em ory system is (o d efine a primitive
p ro ced u re call th a t is g u a ra n te e d to ex clude o th e r calls o f the sam e p ro ce
dure. T h at is, if tw o p rocesses try lo call Ihe sam e p ro c ed u re , only o n e will
succeed and the losing process will have lo w ait. A s usual it is not specified in
which o rd e r sim u ltan eo u s req u e sts are g ran te d .

26

THE CONCURRENT PROGRAMMING A8SIRACTION

CHAP 2

In multiprogramming systems, (he interrupt facility' is used. A critical


procedure is written as an interrupt routine to be executed when a process
causes an interrupt. A hardware flag ensures mutual exclusion by inhibiting
the interruptplacing the computer in an uniittcrrupiable state. Upon
completion of the interrupt routine, the flag is reset and another proccss may
now cause an interrupt.
A nother method of implemcn(ing mutual exclusion is polling. Bach
process is interrogated in turn to see if it requires some service that must be
done under mutual exclusion.
Wc shall allow ourselves the luxury of defining primitive instructions
and, beyond the sketch in this scction, we shall not worry about the
implementation. With some experience in computer architecture and data
structures it should not be too difficult to implement any o f these primitives.
However, the details differ widely from computer to computer. A study of
the implementation kit may help. In the bibliography we give references to
several descriptions of concurrcnt programming implementations. In addi
tion, the serious student should study the architecture of whatever computer
and operating system he is using.
2 .6

CONCURRENT PR O G RAM M ING IN PASCAL'S

Sequential Pascal (and the subset used in this book) must be augmented by
concurrcnt programming constructs. The concurrent processes arc written
as Pascal procedures and their identity as concurrent processes is established
by their appearancc in the cobegin . . . coend s(a(emcnt
cobegin Px; P2; . . P coend.
A request for concurrent execution of several processes may appear only in
the main program and may not be nested. The semantics of the cobegin . ..
coend statement are specified as follows:
The cobegin statement is a signal to the system that the enclosed
procedures are not to be executed but are lo be marked for concurrent
execution. When the coend statem ent is reached, the execution of Ihe
main program is suspended and the concurrcnt processesare executed.
The interleaving of the executions of these processes is not predictable
and may change from one run to another. When all concurrent pro
cesses have terminated, then the main program is resumed at the
statement following the coend.
An additional notational device that we make use of is the statement
repeal . . . forever which is exactly equivalent in its semantic content with
repeat. . until/alse. However, the latter is rather obscure and wc prefer the
more transparent notation.

SECT. 2 *

CONCURRbNI PROGRAMMING IN PASCAL'S

27

The use of repeat . . . forever emphasizes (hat these examples are


intended to be prototypes of cyclic programs in operating systems and
real-time systems.
To execute any of the examples in the book on the implementation kit
you will generally have to do the following. (See Fig. 1.5 and, for a larger
example, Fig. 4.18).
1. Replace repeat . . . forever by a for-Soop that will cxecutc each
process a fixed number of times or otherwise arrange for termina
tion.
2. Insert write statem ents in the main program or in the concurrent
processes to trace the execution of the program.
3. O ften, cerlain procedures have been left unspecified to emphasize
the generality of (he algorithms. For example, in the producer-consumcr problem, we have invoked procedures named produce and
consume. These procedures must be specified. One possibility is to
produce by incrementing an integer and consume by priming it.
4. Warning The interpreter in the kit is very inefficient, so do not get
carried away with the size of the programs that you intend to
cxccute.

2.7

SUM M ARY

This list summarizes the concurrent programming abstraction.


1. A concurrent program will consist of two or more sequential prog
rams whose execution sequences are interleaved.
2. The processes must be loosely connected. In particular, Ihe failure of
any process oulside its critical section and protocols must not affect
the other processes.
3. A concurrent program is correct if it does not suffer from violation of
safety properties such as mutual exclusion and of live ness properties
such as deadlock and lockout.
4. A concurrent program is incorrect if there exists an interleaved
execution scqucnce which violates a correctness requirement.
Hence it is sufficient to construct a scenario to show incorrectness; to
show correctness requires a mathematical argument that the prog
ram is correct for all execution sequences.
5. No timing assumptions arc made except that no process halts in its
critical section and that, if there are ready processes, one is eventu
ally scheduled for execution. We may impose oth er fairness
requirements.

28

T U t CONCURRfcNJ rM O C KA M M IN C ABSTRACTION

CHAP 2

6. We shall extend o ur basic program m ing language with synchroniza


tion primitive instructions. A s long as (he syntax and sem antics of
these instructions are ctcarty defined wc do not concern ourselves
with their im plem entation.

2 .8 EXERCISES
2.1

Standing E zerd se W rite form al specifications o f Ihe program s in this book.


F or example:
Specification for sonprogram.
Input: A sequence o f 40 integers: 4 {a,..........
O u tp u t: A sequence of 40 inlegeis: b = [bl, . . . .
Safety property: W hen the program term inates then (i) b is a p erm utation o f a,
and (ii) b is o rd ere d , i.e. for 1 < * i < 40. b, < m b,+ I.
Livcncss property: T he program term inates.

2.2

Standing Exercise Test (tie exam ple program s in Ihe text.

THE MUTUAL EXCLUSION PROBLEM

3.1

IN T R O D U C T IO N

A solution to the mutual exclusion problem for tw o processes P, and Pz will


now be developed w ithout introducing any primitive instructions (other than
the com m on mem ory arbiter). The purpose of this chapter is not so much to
present D ckker'selcgunt solution to this very difficult problem us to present
D ijkstra's step-by-step developm ent o f D ck k ers solution. During the
developm ent we will encounter most of the possible bugs that a concurrent
program can have and thus illustrate the thcorclical discussion of the previ
ous chapter. The serious reader will w ant to try to analyze each attem pted
solution before reading further.
T he mutual exclusion problem for two processes is as follows:
Two processes P, and P2 are each executing in an infinite loop a program
which consists of two sections, critical sections criil and c ritl and the

32

THE M U T U A L EXCLUSION PROBLEM

C H AP 3

arc a useful pro g ram m in g technique but a system o f co ro u tin es m ust be


designed as a single in teg rated process a n d are not a su b stitu te for co n cu r
rent program s.

3 .3

SECO NO A T TE M P T

K g . 3.3.

Wc try to rem ed y the p revious solution by giving each process its ow n


key lo th e critical section so if one is d ev o u re d by a p o lar b e a r th en the o th e r
can still e n te r its critical section. T h e re is now (Pig. 3 .3 ) an igloo (global
variable) id en tified w ith each proccss. It is w o rth no tin g th a t, while in th e
solution in Fig. 3.2 the variable turn is b o th re a d (l.o a d ) a n d w ritten (S to re)
by b o th processes, th e p re se n t solution m ay be e a sie r to im plem ent because
each proccss re a d s b u t d o c s no t w rite the v ariab le id en tified w ith the o th e r
process.
If P, (say ) w ishes lo e n te r its critical sectio n , it craw ls in to PjH igloo
periodically until it n o te s th at c2 is eq u al to 1 signifying th a t Pi is cu rren tly
no t in its critical section. H aving asce rtain ed th ai fact, P, m ay e n te r its
critical section a fter d uly reg isterin g its e n tra n c e by ch alk in g a 0 o n its
b la ck b o a rd c ,. W h en P , h as finished, it ch an g es the m ark o n e , to I to notify
P2 th at th e critical section is free.
p ro g ra m secondaitem pt;
var
c t, c2: integer;
p ro ced u re p ,;
begin
repeat

SCT. J.3

........... -

SECOND A T ll- M p r

33

while c , 0 do;
c ,:- 0 ;
eril ];
c. ;= J;
rem 1
forever
end;
p ro ced u re p 3\
begin
repeat
while c , = 0 do;
C2
0;
cm 2;
c,
I;
rem 2
forever
end;
begin (* m ain program *)
1;

Ci : * 1;
cobegin
PuPi
coend
end.
F it . 3 .4 .

T his p ro g ram (Fig. 3 .4 ) d o e s no t even satisfy the safety req u ire m e n t o f


m utual exclusion. T h e follow ing scen ario gives a c o u n ter-ex am p le w here the
first colum n d escrib es the in terleav in g a n d the next co lu m n s reco rd the
values o f the variables.
Initially
/ \ checks c 2
P 3 ch eck s c,
P i sets c l
P t sets c2
P x e n te rs c ritl
P t e n te rs crit2

c,
1
1
1
0
0
0
0

c
1
1
1
1
0
0
0

Since/*, and P2 are sim ultaneously in th eir critical sections, the program is
incorrect.

. . . e M U TU AL EXCLUSION PROBI EM

3 .4

CHAP. 3

T H IR D A T T E M P T

program thirdattempi;
var
c c2: integer,
procedure p x\
beg/n
repeat
c, := 0;
while C j=0 do;
crti 1;
Ci
1;
rem 1
forever
end;
procedure p };
begin
repeat
^2 " 0*>
while c, = 0 do;
c r itl;
< , : 1;
re m 2
forever
end;
begin ( m ain program *)
c, : 1;
Cj : * 1;
cobegin
p t.p i
coend
end.
Fit. 3.5.

Analyzing the failure of the sccond attem pt, we note th at, oncc P, has
ascertained th at P2 $ not in its critical section, P, is going to chargc right into
itscriticalscction. Thus, the instant that P , has passed the while statem ent. Pt
is in e ffe c t in its critical section. This contradicts our intention that c, * 0
should indicate that P, is in its critical section because there may be an
arbitrarily long wait betw een the while statem ent and the assignment
statem ent.
The third attem pt (Fig. 3 .5) corrects this by advancing the assignment
statem ent so that t , 0 will indicate th at P, is in its critical scction even
before itch e c k sc 3. Hcncc P, is in its critical section the instant that the while
has been successfully passed.

SECT. 3.

TH IR D AVILM P T

35

U nfortunately (his program easily leads to system deadlock as seen by


the following scenario:
Cl

Initially
P, sets c,
P 2 sets e2
P, checks c 2
P2 checks C|

The continual checking o f (he variables can be continued indefinitely and


cannot be considered progress. Thus the program is hopelessly deadlocked.
Even though this program is unacceptable because of the deadlock, it is
instructive to prove that it satisfies the m utual exclusion property. By sym
metry it is sufficient lo show that: (P , in c ritI) implies (P 2 is not in m /2 ).
1. (W hen P, entered m / 1 ) then (c2 was not 0).
This follows from the structure o f the program , nam ely the test
on c2 by P
2. (c2 is not 0) implies (P 2 is not in c ritl).
c ritl is bracketed betw een assignm ents to c2 which ensure (hat
this statem ent is always (rue.
3. (W hen P, entered crit 1) th en (P 2 was not in eril2).
This is a logical consequence o f (1) and (2).
4. (P, in eril I) implies (c, is 0).
eril I is brackeied betw een a ssig n m e n t (o c,.
5. (c, is 0) implies (P 2 docs not e n te r crii2).
The (est will not allow P2 through.
6. (P, in m / 1 ) implies (P 2 docs not en te r m /2 ).
A logical consequence of (4) and (5).
7. As long as (P , is in crit 1), (P 2 will never en ter m /2 ).
This follows from (6). Since (6 ) refers (o an arbitrary instant of
tim e, then as long as its antecedent (P , in m '/ l ) rem ains true, so
will its consequent (P 2 docs not e n ter cm 2).
8. (P, in crit I) implies (P 2 is not in m /2 ).
From (3) an d (7).
Note that the proof has (he simple structure o f a deduction in the
propositional calculus except for the need (o express and deduce (imcrelatcd properties such as w hen , as long as" etc. T here is a formal logic
called tem poral logic (hat can express these properties and can be used (o
formally prove p roperties of concurrent program s. For exam ple, the reason
ing in this pro o f can be form alized as an induction on the tim e th a t has passed
since P, en tered crit 1. We arc trying to prove that mutual exclusion is never
violated: (3 ) ensures (he basis o f (he induction; (6) is an induction step:
assuming that P, is now in crit 1, we can deduce tha( P2 will not now e n ter

36

I l t r M U tU A l. EXCLUSION PROBLEM

CHAP J

crii2 so th at upon the conclusion o f the current instruction, mutual exclusion


will still not be violated
3 .5

F O U R TH A T TE M P T

program fourthattempt;
v ar Ct, Cji integer,
procedure p ,\
begin
repeat
c, := U;
while C j*0 do
begin
c , : = 1;
( do nothing fo r a fe w m om ents )
c , ;= 0
end;
crit I ;
c, := I;
rem 1
forever
end;
procedure p 2',
begin
repeat
c2 := 0;
while c, = 0 do
begin
Ci : I;
( do nothing fo r a fe w m om ents *)
c ,:- 0
end;
c r itl;
1;
retn2
forever
end;
begin (* main program )
c,
1;
Ci := 1;
cobegin
P i P i

coend
end.

SECT S.S

FOURTH A T I hM K l

37

In Ihe previous solution, when P, chalks up 0 on c, lo indicate its


intention to en ter its critical section, it also turns out that it is insisting on its
right to e n te r the critical section. It is true that s e ttin g s before checking c2
prevents the violation o f m utual exclusion but if P2 is not ready lo yield then
should yield.
In the next attem pt (Fig. 3.6) we correct this stubborn behavior by
having a process relinquish tem porarily its intention to en ter its critical
section to give the o th er process a chancc to d o so. P, en ters its igloo and
chalks up a 0. If upon checking P ,s igloo, P, finds a 0 there too, it chival
rously returns to its igloo lo erase the 0. A fter a few laps around the igloo it
restores the signal c ( 0 and tries again. The comm ent is there simply to
rem ind you that since arbitrary interleaving is permissible, the sequence of
two assignments to the same variable is not meaningless.
First note that the previous proof o f m utual exclusion holds here. From
the above discussion, it should now be clear that there is such a thing as too
much chivalry. If both processes continue yielding then n either will enter the
critical scction. The scenario is as follows:
Initially
P, sets c,
P j sets c,
P , checks ct
P , checks c,
P , sets c ,
P , sets c2
l \ sets C|
P j sets c,

1
0
0
0
0
1
1
0
0

1
I
0
0
0
0
I
1
0

It is d e a r that this could be indefinitely extended and that liveness docs not
hold because neither process will ev er e n te r its critical section. However, it is
extrem ely unlikely ever to occur. N evertheless we are forced to reject this
solution. The main objection here is not so much that n either process will
ever e n te r the critical section (it is unlikely that perfect synchronization
continues indefinitely) but that we have no way of giving an a priori bound
on the num ber of iterations that the loops will execute before they arc
passed. Thus we have no way o f guaranteeing the perform ance of such a
system.
Should this bug be classified as deadlock o r lockout? On the one hand,
both processes are looping on a protocol which is certainly not useful
com pulation and the situation is similar to (he previous attem pt. However,
we prefer to call this lockout to em phasize the following distinction. In the
previous attem pt the situation is hopeless. From the instant that (he program
is deadlocked, all future executions sequences rem ain deadlocked. In this

38

THfc M U TU AL EXCLUSION PROBL EM

CHAP. 3

case however, the slightest aberration of the scenario will free one of the
processes and in practice (his will eventually happen. The key notion here is
the conspiracy betw een the processes and not the hopelessness o f the situa
tion. It is only because we wish to be able to guarantee a worst-case behavior
(hat we reject the current attem pt.
3 .6

OEKKER'S ALGORITHM
program
var

D ekker,
turn: integer,
c c2: integer;
procedure p x\
begin
repeat
c, := 0;
while c2 = 0 do
if turn * 2 (hen
begin
c, := 1;
while lu rn 2 do;
c ,:- 0
end;
cril 1;
turn := 2;
c, := 1;
rem I
forever
end;
procedure p t :
begin
repeat
c , := 0;
while C| 0 do
If tu rn * I then
begin
e , : 1;
while turn= 1 do;
c2
0
end;
crit2\
. turn : = 1;
c2 := 1;
rem2
forever
end;

SECT. i 6

D tK K b R 'S A I O O H IIIIM

3V

begin (* m ain program )


c.
I;
ci
1;
tu n i : = 1;
cohcgin
Pi>Pt
coend
end.
Ft*. 3.7.
D ekkers solution is an ingenious com bination o f (he first and fourth
attem pted solutions. Recall that in the first solution we explicitly passed the
right to e n ter the critical section betw een the processes. U nfortunately, the
key to the critical section could be irretricvablcy lost if one o f the processes is
term inated. In (he fourth solution we found that keeping separate keys leads
to the possibility o f infinite deferm ent of one process to the other.
D ekker's algorithm (Fig. 3.7) is based on the previous solution but
solves the problem of lockout by explicitly passing the right to insist on
entering the critical solution. Each process has a separate igloo so it can go
on processing even if one process is term inated by a polar bear. Note that we
are here using the assum ption th at no process is term inated in its critical
section (including the protocol).
There is now an um pire igloo with a blackboard labelled "turn", (Fig.
3-8). If P, chalks up a 0 on e, and then finds that P2 has also chalkcd u p aO , it
goes to consult the umpire. If the um pire has a 1 w ritten upon it, then P,
knows that it is its turn to insist and so P, periodically checks P2's igloo. P2 o f
course notes that il is its turn to defer and chivalrously chalks u p a I on c2
which will eventually be noted by P,. P? m eanw hile w aits for P, to term inate

Fig. 3.8.

40

THfc M U J D A L EXC LU SIO N PKODI EM

CHAP J

its critical section. U pon term in a tio n . P, n o t only frees the critical section by
se ttin g c , to I but also resets turn to 2 b o th to free Pt from Ihe in n e r loop anil
to tra n sfer the right to insist to Pt .
M utual exclusion is p ro v ed exactly a s in S ection 3.4 since the value of
turn has no cffect o n the decision to e n te r the critical section.
P roving livencss is som ew hat o f a ch allenge. S ym m etrically it is suffi
cient to prove th a t, if P x ex ecu tes c, : = 0 indicating its in ten tio n to e n te r the
critical section, th en ev entually il d o cs so. T his is d o n e in tw o parts. First we
prove th a t if P, a tte m p ts to e n te r its critical section but c a n n o t d o so,
eventually the v ariable turn is p e rm an en tly lield at (he value I . B ut if turn is
held perm an en tly a t 1 th en P, can alw ays e n te r its critical section.

3 .7 A P R O O F OF D E K K E R 'S A L G O R IT H M

Let us now prove th e livencss o f D e k k e rs A lgorithm . The algorithm is


show n in flowchart form in Fig. 3.9. T he form al sta tem en t th a t we w ant to
p rove is th at if the pro g ram co u n te r o f process/*, is a i point a ; (i.e. P t h as left
rent 1 and thus ex p resses a wish to e n te r th e critical sectio n ), ev entually the
program co u n ter o f /*, will be at <*j (i.e. P , may e n te r the critical scctio n ). O f
course an cxactly sym m etrical p ro o f will prove th e livencss o f Pt .
O u r n o ta tio n will be m ore concisc: a , will be an ab b re v ia tio n for the
sta te m e n t th a t th e program c o u n te r of P t is a t a,. Sim ilarly fo r P2 a n d f},.
R em em b er th e assu m p tio n th at a process is n e v er te rm in a ted in its
critical section (including the p rotocols). T hus if P x is at a b, il will eventually
reach a a. If P, is at a , , il will ev entually reach 4 o r
th o u g h w ith o u t fu rth er
in fo rm atio n we c a n n o t specify w hich o f th e tw o sta te m e n ts will be reachcd.
T o simplify the p roof, this assu m p tio n isc x le n d c d to rem i ( a , a n d 0 ,) . In the
exercises wc indicate the m odifications n eed ed if we allow /*, to term in ate in
retni.
N o te th a t if P t is a ta ^ a n d c 2 * 1, we can n o t co n clu d e thut ev entually P,
is at a j . T h e assu m p tio n only g u a ra n te e s th a t /*, e v en tu a lly te sts the value of
c 2; by th e n the value o f Cj co u ld have b een changed. To co n clu d c th a t a 3
im plies ev en tu ally <* we w ould have to show th a t a , a n d th a t th e value o f r 2 is
held at 1 indefinitely. T h u s, w hen by assum ption Ihe test is e v en tu ally done,
th e value o f c 2 will in fact be 1.
Since the only assig n m en ts to e , are in P we can d ed u ce th e values o f c(
from the a s an d th e /3s, respectively. W e express th ese facts as invariants,
i.e. sta te m e n ts th at a re alw ays tru e.
11. c, = 0 if a n d o nly if a , o r a o r a , o r a o r a 7.
12. Cj = 0 if and only if /3j o r
o r o r 0* o r $ v

Fig. 3.9

Oekkcr'i Aljorirtim. Iniiial values: c t - c : ~turn j.

42

THE M U TU AL EXCLUSION PRQBLbM

Theorem

CHAP 3

(a 2 and never a , ) is false, th at is a , implies eventually a s.

P roof
1. ( a 2 and never a , ) and (turn held at 2) imply eventually (c, held at 1).
Since (never a j) , Pt eventually passes a , and thence t o a 4. Since
(turn held at 2), P, reachcs <*6 and or* and is then blocked in the
loop at a #. By 11, as long as P, is at ora, c, must equal 1.
2. (c, held at 1) and (turn held at 2) imply eventually (turn 1).
The truth of the two clauses concerning c, and turn together with
the assum ption that processes arc not term inated implies that P2
must eventually reach 0 7 and assign the value 1 to turn.
But (turn held at 2 ) and eventually (turn - I) m eans that there
will be a point of tim e when turn is sim ultaneously 1 and 2. This
contradicts the consistency o f the values in the com m on memory.
From ( a 2 and never <*j) and (turn held at 2) we have deduced a
contradiction. Thus it must be that ( a 2 and never a s) implies
eventually (turn is not 2). Since turn * 2 or turn * 1 we have
proved.
3. (a 2 and never <*j) implies eventually (turn = 1 ).
4. ( a , and never a*) implies (never a s) and (never a T) and (never a ,) .
The only way to reach a , o r a Tfrom a 2 is to pass through a y But
wc assume that wc never reach a y
5. (a 2 a n d never a s) implies eventually (turn held at 1).
Once the value of turn is 1 (as ensured by (3 )) the only way that
the value can changc back to 2 is to execute a , . By 4 this will
never happen.
6. ( a , and never a , ) implies eventually (P , loops forever at o ,-o t4)By (4) and (5), cventuallyf(<r/r held at 1) and (P, is never at a s)].
H ence since P, must reach aj-ft fro m a ,,a r4o r a , it will then loop
forever at a j - a 4.
7. ( a 2 and never a*) im plies eventually (c, held at 0).
By (6), eventually we loop at j-ar4 which implies by 11 that ct will
be held at 0.
8. (c, held at 0) and (turn held at 1) imply eventually (cj held at 1).
Similar to (1): P 2 must eventually lo o p at/3 .T h en b y 12, c 2 is held
at 1.
9. ( a , and never a t ) implies eventually (c2 held at 1).
From (5), (7 ) and (8).
But (8) contradicts (6): if c2 is held at 1 then P, cannot be looping

seci.

CONCLUSION

43

at <k3- a 4. From ( a 2 and never a , ) we have deduced a contradiction. Thus ( a 2 and never a>) is false.
3 .8

C O N C L U S IO N

M utual exclusion of tw o processes is about the simplest problem in concur*


rent program m ing. T he difficulty of obtaining a correct solution to such a
simple problem suggests that program m ing features m ore powerful than the
comm on mem ory arb iter will be needed. In the exercises you can explore
some other solutions o f the type given here.
In particular, the solutions o f the m utual exclusion problem for n
processes arc so difficult that they are of more or less academ ic interest only,
especially when com pared with the trivial solution to the problem given, say,
by sem aphores.
T here is another defect in the com m on mem ory a rb iter and that is the
busy wail that is used to achicve synchronization. T he solutions atl contain a
statem ent; while condition do (* nothing ). Unless you have a dedicated
com puter doing the looping this is a waste o f CPU com puting pow er. Even if
there is no CPU waste (as would be the case if the processes were I/O
controllers) there is the severe overhead associated with cycle stealing. Thus
the frequent accesses to turn in D ek k ers solution can prevent useful com pu
tation from being done by o th er processes.
The primitives discussed in the next chapters uniformly suspend the
execution of the blocked processes. This is usually im plem ented by keeping
a queue of processes, i.e. a queue of small blocks o f mem ory containing
essential inform ation on the blocked processes. Thus the overhead is only a
small am ount of mem ory and the small am ount of com putation needed to
manage the queue.
A final objection to D ek k ers algorithm is that it uses a common
variable which is w ritten into by both processes. In th e exercises wc discuss
L am ports algorithm s which have th e advantage that each variable need only
be w ritten by one process. T hus his algorithm s arc suitable for im plem enta
tion on distributed systems w here the values o f the variables can be trans
m itted and received but w here each variable is w ritten into only on the
com puter in which il physically resides.
3 .9

EXER CISES

3.! (DijksUa) Fig. 3.10 is u solution to the mutual exclusion problem for n processes
that is a generalization of Dckkers solution. .
(a) *Show that mutual exclusion holds.
(b) Show that deadlock does not occur.
(c) Show ihat lockout is possible.

44

1 Hb M ID UAI. EXCLUSION PROBLEM

CHAP 3

p ro g ra m Difksira;
const
= . . . ; ( n u m b er o f processes )
var
b , c: a rr a y (0 . . n ) o f
boolean,
turn: integer,
p ro c e d u re p ro cess(i : integer)',
v ar
/: integer-,
o k : boolean;
begin
rep eal
b(i]false;
rep eat
w hile tu rn < > i do
begin
<(j)
true;
i f b{lurn) Ihen turn := j
end;

c {/J : fa lse;
o k := true;
fo r j : m 1 lo a do
If / < > then
o k : =* o k a n d cf/'J
u n til o k ;
crit;

eCO lrue MO

,rue>

turn
0;
rent
fo rev er
end;
begin ( m ain program )
fo r turn : * 0 to n do
begin
b{turn] := true;
c\lu rn ) : = true
end;
turn : 0;
cobegin
p r tx e s s { \) ,
p roct4s{2);
process(n)
coend
end.
Fig. 3.10.

3.2 ( I j m p o r i ) Fig- 3.11 is (w hat the A u th o r calls) th e D u tch B e e r version o f the


B akery A lg o rith m , reslriclcd lo tw o processes.
(a ) S how safely an d liveness. (H in t T h e variables a re supposed to rep resen t
' tic k e t" n u m b e rs". T he process w ith ihe low er tick et n u m b e r e n te rs its
critical section. In case o f a tic, il is a rb itra rily resolved in favor o f P (.)
(b ) Show th a t the co m m an d s
: 1 a re necessary.
b t 'r d

EXEKCISfcS 45

(c) E xtend ih e alg o rith m lo n processes. ( H i m E ach proccss will chouse a


Jickcl n u m b er g reu tet th an Ihe m axim um o f all o u tsta n d in g ticket num bers.
Il will th en w ail until all processes w iih low er n u m b ered tickets have
com pleted th e ir critical sections.)
p ro g ram dutchbeer,
v ar
n ,.
integer;
p ro ced u re />,;
begin
rep eat
*i

I;

fl, : n , + l;
while (si2 < > 0 ) a n d (n 2 < " ) do;
crit 1;
: 0 ;

rem I
forever
end;
p ro ced u re p 2;
begin
rep eat
2

/ij : f|+ I ;
w hile (/i, < > 0 ) a n d ( n , < - n 2) do;
c h /2 ;
/i2 : * 0;

r e tn l
forever
end;
begin ( m ain program *)

fl,

0;

n 2 := 0;

cobegin
P1 IP 2
coend
end.
Fig. 3.11.

3.3 Fig. 3.12 is L am p o rts B akery A lgorithm restricted 10 iw o processes.


(a )
(b )
(c)
(d)

Show ihe safely an d liveness o f (his solution.


G eneralize to n processes.
Show (hal for n > 2 Ihe values o f the variables n , are nol bounded.
'S u p p o se wc allow a re ad (i.e. I.o ad ) o f a variab le n, 10 re tu rn any value if il
lak es place sim ultaneously w ith a w rite (S to re ) o f n , by the ith process. Show
thai Ihe co rrectn e ss o f (he algorithm is n o l affected . N o te, how ever, th at we
require the w rite lo execu te correctly. Sim ilarly, all read s which do not
o v erlap w rites lo the sam e variable m ust re tu rn the co rrect values.
(c) Show th a t (he co rrectn ess o f ihe D u tch B eer v ersion o f the alg o rith m is not
preserv ed u n d er th e m alfunction d escrib ed in (d ).

46

THE MUTUAL EXCLUSION PROBLEM

CHAP 3'

program bakery,
var
f | . <2. i. j- integer,
procedure p t \
begin
repeat
e,

1;

i := 2+ l ;

c,

0;

while Cj < > 0 do;


while (/i2 < > 0 ) and (/i2 < ,) do;
crit I ;
n , : 0;
rem I
forever
end;
procedure p lt
begin
repeal
f 2:" li
rt2
" j + l;
0;

Ci

while c, < > 0 do;


while (n , < > 0) and ( , < /ij) do;
cm 2;
" i : 0;
f#m2
forever
end;
begin ( main program )
0;
c2 : - 0 ;

fl, := 0;
n2

0;

cobegln
PuPl
coend
end.
Fig. 3.12.

3.4 Fig. 3.13 is a solution lo ih e m utual exclusion problem for two processes. Discuss
ihc correctness o f the solution: if it is corrcct, then prove it. If not. write scenarios
that show (hat the solution is incorrect.
Several sychronizaiion primitives that have been used are based on hardware
instructions th at enable several assignment statem ents to be executed as one
(indivisible) primitive instruction. The solutions to the m utual exclusion prob
lem using these primitives are very simple, but they rem ain busy wait algorithms
in contrast to algorithm s using the primitives to be studied in the next chapter.

E X tR C IS tS

;
t
f
:

47

program attempt',
var
e ,. cy. integer,
procedure />,;
begin
repeat
rem 1;
repeal
c,

I - c2

until Cj < > 0;


c ritl;
e, := 1
forever
end;
procedure p t \
begin
repeat
rem2,
repeal
c , 1 - c,
until C| < > 0;
cm 2;
cj

forever
end;
begin ( /nat'/i program *)
e,

1;

ct

1;

cobcgin
Pi i Pl
coend
end.
Fig. 3.13.

3.S The IBM 3 6 0 /3 7 0 com puters have an instruction called T S T (Test and Set).
There is a system global variable called e (Condition Code). Executing TST(i)
for local variable / is equivalent to the following two assignments:
I
c

c;
I.

(a) Discuss the correctness (safety, deadlock, lockout) o f the solution of the
m utual exclusion problem shown in Fig. 3.14.
(b) Generalize to n processes.
(c) W hai would happen if the primitive T S T instruction were replaced by the
two assignments?
(d) Modify the im plem entation kit lo include the T S T instruction.

48

IHfc MUTUAL EXCLUSION PROBLEM

CHAP. 1

p ro g ra m teu a n d iet,
var
c: integer,
p ro c e d u re /,;
var
/: integer;
begin
rep eal
r e m) ;
rep eal

7571(0
u n til / * 0;
crit 1;
c
0
fo rev er
end;
p ro c e d u re p i,
var
I: integer,
begin
re p e a t
rem2;
re p e a t
T 5 T (l)
u n til / = 0;
criQ ;
c

fo rev er
cad;
begin ( m ain program )
c : 0;
cobegin
Pi> P i
coend
end
llg . 3.14.

3 .6 T he E X in stru ctio n ex changes th e c o n te n ts o f iwo m em ory locations E X (a ,b ) is


eq u iv alen t to an indivisible execution o f the follow ing assignm ent statem ents:
tem p : a;
a : - b;
b : tem p.
(a )

D iscuss the co rrectn ess (safety, d ead lo c k , lo ck o u t) o f the solu tio n fot
m u lu al exclusion show n in Pig. 3.15.
(b ) G en eralize to n processes.
(c ) W h at w ould h ap p en if the prim itive E X in struction w ere rep laced by the
ih ree assignm ents?
(d ) 'M o d ify th e im p lem en tatio n kii to include the E X instruction.

fcX K R C im

4V

p ro g ram exchange;
var
c: integer;
p ro ced u re p \;
v ar
/: integer;
begin
/ : 0;
rep eal
rem 1;
rep eal
E X (cj)
until / - 1;
crit 1;
E X {cj)
forever
end;
p ro ced u re p y,
var
/: integer;
begin

0;
repeal
re m 2;
rep eat
E X ( Cj )
u n lii I I;
m /2 ;
AT (c,/)
forever
end;
begin ( /noin pro gram )
c := I;
cobegia
P i; P i
coead
end.
Fig. 3.15.

3.7*lf wc allow P2 to term in a te in rem 2, w hat ch an g es n e e d lo be m ad e in th e proof


of the liveness of D c k k c r's alg o rith m ? (H in t U P2 s te rm in ate d in rem 2. ihen it
is true by 12 th a t c 2 h h eld at I)-

4 .1

SEMAPHORES

IN T R O D U C T IO N

The scicntific study o f concurrent program s was given a decisive thrust with
the introduction o f the sem aphore by D ijkstra. Sem aphores are easy lo
im plem ent and yet sufficiently pow erful that they can he used to give elegant
solutions to concurrent program m ing problems. They can be used to define
or im plem ent more powerful structured primitives.
A sem aphore s is an integer variable which can take on only non-zero
values. Once s has been given its initial value, the only perm issible opera*
tions on s are to call the procedures wail(s) and signal(s) which are primitive
operations (the original notation is P(s) for wait(s) and K(j) for signal(s),
which are the first tetters of the corresponding w ords in D utch). T he defini
tion of these operations is as follows:
wait(s): U s > 0 t h e m := s - 1 else the execution o f the process that called
H'ait(f) is suspended.
signal(s): If som e process P has been suspended by a previous >v<m(;)on this
sem aphore s then wake up P else s : s + 1.
R em ark 1 If the sem aphore only assumes the values 0 and 1, it is called
a binary sem aphore. A sem aphore which can take arbitrary non-negative
integer values is called a general semaphore.
R emark 2 wail and signal are the only operations allowed. In particular,
assignm ents to s or tests of the value of s are prohibited except for an
assignment to s o f an initial non-negaiive value in the main program . (The
im plem entation kit does not enforce this restriction nor does it distinguish
binary from general sem aphores.)
Remark 3 We have defined the procedures as primitive operations.
This m eans that they exclude one a n o th er just as Load and Store to the same
50

SECT 4 i

M U TU AL EXCLUSION

$1

memory word cxcludc one anoiher. (Sem aphore operations on distinct


Semaphores need not cxcludc one another). Hence if a wait and a signal (or
two hwi/s o r two signors) occur simultaneously (hey arc executed one at a
time though we do not know in whai o rd e r they are executed.
Remark 4 The definition o f signal does not spccify which process is
woken if more than one process has been suspended on the sam e semaphore.
For Ihe purpose of constructing a scenario you may assume that any proccss
you wish is in fact selected. A FIF O sem aphore which m aintains a first-in,
first-out queue of suspended processes could also be defined. Tlere are
more sophisticated definitionsof fairness but that isa slightly m ore advanced
topic and we suggest that you skip it on the first reading.
{A dvanced) Rem ark 5 T he classical (busy-wait) definition of sema
phores is even weaker:
M'arr(j): W hen s > 0 ihen s : s - 1.
R ead this as: w henever the value o f s is greater than zero, th e proccss
may cxccute s
s - I and continue.
signals): s := s + 1.
Suppose that process P e x e c u t e s ^ / i t f ^ ) when the queue contains the
blocked processes Q x, . . . . Qk. T his definition does not guarantee that
any o f the Q ,........... Qk a re w oken. The interleaving o f execution
sequences allows any process (even P) to execute h-<m/(j) and decrem ent
s before any o f Q ........... QK have a chance to d o so.
A nother definition is that of the strongly fair sem aphore which is
assumed to have the following property:
If P is suspended on s and s bccom es greater than zero infinitely often
then eventually signal will choose to wake P.
(End o f R em ark 5).
4 .2

M U T U A L E X C LU S IO N

Figure 4 .1 is a solution to the m utual exclusion problem using sem aphores.


program m uiualexclttsion;
var
s: ( binary ) sem aphore;
procedure p x\
begin
repeat
wait (*);
crii I ;
sig n a ls);
rem 1
forever
end;

S3

CHAP 4

SEM A PH O RES

p ro c e d u re

p 2;

b e g in
re p e a t

wait(s);
cr/72;
signals);
re//i2
fo r e v e r
end;

begin (* main program )


s ; I ;
cobcgin
P ii Pi
coend
end.
F it . 4.1.

All the synchronization is veiled by th e powerful features o f the


sem aphore. T h at is the way it should be. Language features are defined;
compiler writers and systems program m ers figure out how lo im plem ent it;
and everyone else uses the feature with a reasonable assurance that it will
work.
Let us exam ine this algorithm in detail with the aid of the igloo model.
O ur igloo (Fig. 4 .2) now has in addition to its blackboard a deep-freezer. A
process enters and perform s a wait: ifih crc is a I on the board it can en ter Us
critical section; otherw ise, it goes into hibernation in the freezer. Note that
once a process e n ters the freezer it has cleared the interior o f the igloo and

Fig. 4.2.

'I

SECT. 4.2

M U TU AL EXCLUSION

53

another process can en ter even (hough (he first proccss has not actually
com pleted the execution of the wait. As an im plem entation detail, the
freezer ( queue o f suspended processes) must be large enough lo contain
the num ber of processes in the system o r at least the num ber o f processes
that may be wailing on (he sem aphore s.
U pon com pletion of the critical section, the signalling proccss enters the
igloo and releases a process from the freezer. If there are no such processes,
it simply chalks up a one to indicate that the critical section is free. In the case
of a binary sem aphore, a signalling process will always find a zero on the
board (why?). If (he blackboard o f a general sem aphore has any non-zero
number w ritten on it, ihe process can deducc th at the freezer is empty
(why?).
This solution to the m utual exclusion problem is very similar to one of
our earliest attem pts in the previous chapter in which we had the processes
pass the key to the critical section back and forth. We are saved from trouble
here by the fact that the testing of s and the selling of s to zero are
encapsulated in one primitive instruction. Thus if P, notes that s is I . it will
set 5 to 0 before P t has a chance to test the value of s.
M utual exclusion and absence of deadlock are easy to show from the
following property o f the program : s will have Ihe value zero if and only if
exactly one proccss is in its critical section. This can be formally proved as
follows. C onsider the value of the expression E ms + the num ber o f processes
in a critical section. C ertainly E m 1 at the start of the concurrent program
since j = 1 and no process is in a critical section.
Now use the following inductive argum ent. A ssum e that = 1 at any
point in any interleaved execution sequence. The execution sequence con
tinues by choosing to execute cither a step of P , or a step o f P ,. Wc argue by
inspecting the program that in any case the truth o f E - 1 is preserved. Hence
by induction, E - l is always true because any execution sequence is con*
structed starting from the initial state by successively choosing either a step
of P t or of P2. For exam ple, if E - 1 because there are no processes in the
critical scction and $ = l . P t can choose lo en te r the critical section by
executing wait(s). It leaves $ = 0 and num ber o f processes in the critical section
* 1, i.e. * 1 .
The form ula E m 1 is called an invariant of the com putation. Invariants
are proved by induction. The initial state of the com putation satisfies the
invariant and every transition between possible stales o f the com putation
preserves the truth o f the invariant. To prove this, wc assume the truth of Ihe
invariant as an induction hypothesis and Ihen chcck th at the invariant is still
true in the new state resulting from the transition.
Note that, even in this simple case, the full p roof is rath er tedious since
the induction step must be proved for every pair: (location o f P ,'s program
counter, location o f P 2*s program counter). O f course, most steps arc trivial.

54

SEMAPHORES

CHAP 4

The only ones needing any reasoning are executions of the sem aphore
instructions.
We are now in a position to prove the liveness of the solution.
Theorem (P , wishes to en ter crit 1) implies eventually (P , enters cm/1).
P roof
1. (P , wishes to en te r c rifl) implies eventually (P , enters c rifl) o r (P , is
indefinitely suspended because j * 0 ).
2. (P , is indefinitely suspended because x - 0 ) im plies (P 2 is in crit2).
This follows from the invariant E - 1 and the fact that tltere arc
only two processes P, and P 2.
3. (P 2 is in c ritl) implies eventually (P 2 executes *ig</($)).
Wc assum e that no process is term inated in its critical section.
4. (P j executes sig n a ls)) and (P t is indefinitely suspended because 4=0)
implies (P , en ters crirl).
See the definition of the signal operation.
5. (P , wishes to e n te r critX) implies eventually (P , enters cWfl).
The possibility that P, is indefinitely su sp e n d e d o n y = 0 has led to
a contradiction.
Remark N ote that in (4) we have tacitly used the fact that there are only
two processes. O therw ise we could not prove that P, enters its critical section
and not som e o th er process.
(A dvanced) Remark (4) of course does not hold under the busy-watl
definition of sem aphores. In fact lockout is possible under that definition if
the signalling process executes an o th er wait before the suspended process
notes t hat s > 0. H owever, fair sem aphores are sufficient to prove absence of
lockout though a proof such as o u rs would have to be invoked inductively so
that eventually some signal would in fact wake P,.
(E nd o f A dvanced Remark).
The niutal exclusion problem for processes is solved by the identical
program (Fig. 4.3).
procedure mutualexclusion;
const
num ber o f processes )
var x: (* binary *) sem aphore;
procedure process(i: integer);
begin
repeat
wait(s);
crit;

M U TU A L EXCLUSION

SKCT 4 2

55

sig n a ls);
rem
forever
end;
begin (* m ain program *)
s := J;
cobegin
process(l)',
proctss(2)\
process(n)
coend
end.
F ig. 4.3.

In this ease lockout is a possibility. Suppose th ere are three processes


and that the arbitrary choice o f a process woken by signal is such that the
proccss with the lowest index is always chosen. T hen P3 could be indefinitely
delayed as P, and Pt conspire to wake each o th e r up.
(Advanced) Remark M orris has found a lockout-free solution to the
mutual exclusion problem for n processes. T he solution is very complex and
uses additional variables and sem aphores to set a limit on the si2e of a
"batch" of processes that may sim ultaneously wait on the sem aphore used
for mutual exclusion. Since every process eventually com pletes its critical
section and leaves the batch, all these processes will be eventually processed
before a new batch is allowed to com pete for m utual exclusion. T he solution
depends on the definition of sem aphores that requires a signalling process to
wake a waiting process.
(End of A dvanced R em ark).
Consider the problem of allowing at most k out of the n processes lo
simultaneously access the critical scction. For exam ple, a com puter with two
printers could allow tw o jobs to be printed sim ultaneously. T he only change
needed is to initialize the sem aphore to k. k processes wilt successfully
decrement s until its value is zero. T hen a process must wait until one of these
k processes com pletes its critical section and signals. We can see here that it
is necessary for signal also to be a primitive instruction. Otherw ise if k - 3.
** 1 and two processes leave their critical sections sim ultaneously then the
concurrcnt execution could leave
2 even though all processes are now out
of their critical sections.
Can this be done using binary sem aphores only? The answ er is yes. but
the solution is difficult. In the Exercises you can study the solution found by
Kcsscls and M artin (1979).

56

4.3

SEMAPHORES

CHAf. 4

THE PRODUCER-CONSUMER PROBLEM

Along with m utual exclusion, the producer~consum er problem isanabslrac*


tion of applications: of concurrent program m ing that are found throughout
operating systems. Wc choose lo introduce this problem here bccausc (he
sem aphore has a natural interpretation in term s of the produccr-consum er
problem and because D ijkstra's presentation offers another elegant series of
solutions to a concurrcnt program m ing problem .
The producer-consum cr problem arises bccausc Ihc producer of dala
must have som ewhere to store it until the consum er is ready and the
consum er must not try tu consum c d ata th at is not there. It is perfectly valid
to require that a rendezvous betw een the two must lake place. Then the
producer produces if and onty if the consum er is ready to consum c. If either
process arrives early then it is required to wait. The rendezvous is the
reasonable thing to d o unless the tw o processes have a comm on memory, ti is
the basis of (he A da synchronization primitives.
If. however, the dala rales of the producer o r the consum er vary during
the execution of the program then buffering is neccssary. An exam ple is the
type-ahead feature found on most term inal systems. The user is allowed to
produce several com m ands w ithout waiting for the com puter to consume
each command. Similarly, the com puter may produce more information
than can be conveniently presented on the term inal screen. A buffer is used
to average out such peak data rates.
A buffer is a segm ent o f mem ory com m on to both the producer and the
consum er. If the buffer is large enough to handle peaks of data production,
both producer and consum er maintain a steady high average rate of dala
transfer w ithout fearing a malfunction because o f occasional peaks. The
operation of a buffer is the sam e as that of a shock absorber in a car which
stores a peak of energy and then releases it slowly so that both the car and its
occupants can tolerate this input of energy. If a bum p is hit which is beyond
the capacity o f the shock absorber or if the bum ps arc produced at a rate too
rapid to allow the shocks lo be consum ed by a slow release of energy, then
ihc result is unfortunate for the ow ner of ihc car.
A related use o f buffers is to accom m odate I /O equipm ent that accepts
only aggregates o f data. Disks and tapes can read and write only blocks of
re p e a t

produce record v\

b[in] := v ;
in := in f I
fo re v e r;

THE PRODUCER-CONSUMER PROBLEM

57

It. Many terminal system s require that com plete messages be transmilted

lead of individual characters. Even though both the producer and (he
insumcr may be working at (he sam e average rate, the artificial imbalance
used by blocking the data requires th at buffering be used.
For now, let usassum e that wc have an infinite buffer. In programming
Dotation (his can be expressed as an infinite array: fr[0],6(i].............The
producer can then simply pour his d ata into the buffer (Pig. 4.4) (m is a
global variable that counts Ihe num ber o f records produced). The consum er
on the other hand must assure that it is nol consuming from an empiy buffer
(Fig. 4.5) (out is a variable that counts th e num ber of records consumed).
Initially we set i r t - o u t - 0. Note that we have abstracted away many details
of the actual buffering process, in particular the structure of the records and
Ibc processing lo be d one with them. However, the m ain idea of buffering is
C aptured.

repeal
wail until in > our,
w : b{out],
out
out + 1;
consume record w
forever;
Fig. 4.5.

fe .
}; . >
OUT)

IN ]

Fig. 4.6.
Ix t s Min - o u t (Fig. 4.6). s is then the num ber o f records in the buffer.
What values can s lake? s is initially 0. s can increase and then decrease
arbitrarily except that if s reaches 0 ihen the consum er will refuse to reduce s
below 0. Instead it w aits until the producer places another value in the
buffer. If we arrange for the producer to force the consum er into immediate
consumption of this new value then 0 = w - o u / = ( m + l ) - ( o i + 1 ).
s behaves like a sem aphore. In fact the statem ent wait untii in > out in
the consum er can easily be im plem ented by waif(5) assuming th at signal(s) is
added to the producer to wake up the consum er. Thus a solution lo the
producer-consum er problem can be w ritten as show n in Fig. 4.7 (where we
have further abstracted the buffer m anipulations by append (to buffer) and
lake (from buffer)).

58

SEMAPHORES

p ro g ra m
var
p ro c e d u re

CHAP. 4

pruducerconsumer;
n: semaphore;
producer,

b e g in
re p e a t

produce;
append;
signal(n)
fo re v e r
end;
p ro c e d u re

consumer;

b e g in
re p e a t

waii(n);
take;
consum e
fo re v e r
end;

( main program )
n := 0;

b e g in

c o b e g in

producer; consum er
coend
end.
F t*. 4.7.

Thus the sem aphore can be viewed as counting the difference between
the num ber of signals sent by signal and the num ber of signals received by
wail. It is the m ere fact o f signalling that is being counted and not the contcnt
of the signal. A sem aphore can be im plem ented by a message passing system
though it is wasteful to use the fixed size message elem ent to transm it a null
message.
4 .4

M O RE O N THE P R O D U C E R -C O N S U M E R PROBLEM

We now describe a series of solutions to the produccr-consum er problem


under a different hypothesis than in the previous section. Let us assume that
the statem ents append and lake are critical sections that must not overlap.
(Advanced) R em ark A buffering system may be im plem ented as a
chain o f small buffers linked together. O btaining or releasing a small buffer
is usually a critical scction to ensure the consistency o f the pool o f free
buffers. A nother com m on situation th at requires m utual exclusion is the
case of m ultiple producers or consum ers. For exam ple, all the term inals in a
transaction processing system might place their request in a single queue;

ii
MORE ON H IE PRODUCER-CONSUMER PROBI liM

E C T 4.4

5V

would be an instance of multiple producers. If a second processor were


ided to Ihe system to im prove its perform ance, we would have multiple
turners.
:nd of A dvanced R em ark).
In the program in Fig. 4.8, a (binary) sem aphore s is used in addition to
'the general sem aphore n to achicve m utual exclusion.
var

producerconsumer;
n: semaphore,

p ro c e d u re

s: ( binary *) sem aphore;


producer,

p ro g ra m

b e g in
re p e a t

produce;
waii(s);
append,
signal(s)\
signal(tt)
fo r e v e r
end;
p ro c e d u re

consum er,

b e g in
re p e a t

waii{n),
wail(s)\
take;
signal(s)\
consum e
fo re v e r
end;
b e g in * (*

m ain program *)
n := 0;
s := 1;
c o b c g in

producer, consum er
^

coend
end.
Fig. 4.9.

.
*
t
*.
1

Suppose that a program m ing bug was m ade and th a t instead of


signal(s), signal(n) w as w ritten signal(n)\signai(s). This shouldnt affect the
safety of the solution because the solution must be safe even if the interleaving is such that the two s i g n a l are executed successively with no intervening
statem ents from o th e r processes. It is conceivable that the liveness could be
affected sincc the release o f one waiting process out o f tu rn could allow it to

60

SEMAPHORES

CHAP. 4

conspirc against o ther processes. T here is an exam ple of this in th e lockout* 1


free algorithm of M orris m entioned earlier. In this case, fortunately, such a 1
bug does not affect the livencss. T he consum er m ust w ait on both 1
sem aphores before consuming. Since a signal is never blocked and there is |
only one waiting proccss, it docs not m atter in which ord er the signals are I
issued. If the consum er is released from the wait(n) by signal(n) it will still be ]
prevented from takeing prem aturely by *vo//(,s).
J
On the o ther hand, exchanging the wails is fatal. C onsider the following I
simple scenario: the consum er executes wail(s) which issuccessful (because! 1
is initially 1) and then it is blocked by waii(n) (bccause n is initially 0). But 3
now s is 0 and the producer will never be able to append to the buffer. Thus J
the system is deadlocked.
1
This shows up a serious weakness of sem aphores. T here is no way to \
conditionally e n te r o r leave a wail; n or is there a way to exam ine Ihe value of :l
the sem aphore w ithout executing a wait and becoming vulnerable lo being '
blocked. A m ore powerful primitive which does nol have (his w eakness is the ;
conditional critical region. This region evaluates an expression on the ordi- j
nary program variables unlike the sem aphore variable which is not freely i
accessible. For ihe tim e being, we continue o ur discussion of the low level ,
sem aphore and later we return lo more powerful primitives.
An advantage of sem aphores is th at they arc easy to im plem ent; in
particular, binary sem aphores are simple lo im plem ent bccause we d o not
have to worry about ihe maximum value that needs to be provided for as is
the case with ihe general sem aphore. O ne bit is enough. T he next solution
(Fig. 4 .9) lo the producer-consum er problem is by binary sem aphores only.
O fcoursc we will need an integer variable n to count the n um ber of elements
in the buffer since th a t inform ation will no longer be stored in the
sem aphore. T he sem aphore delay will block th e consum er if the buffer is
emply.
producerconsumer,
n: integer,
s : ( binary *) sem aphore;
delay: (+ binary *) semaphore',
procedure producer,
begin
repeal
produce-,
waii(s);
append;
n
/i+ l;
i f 1 th e n signal(delay);
signal(s)
forever
end;
p ro g ra m
var

|C 1.4 4

M ORfi ON THE PROOUCbR-CONSUMER PROBLEM

61

procedure consumer;
var m: integer; ( a local variable )
begin
wait(delay);
repeat
wail(s);
take;
n := n - 1 ;
m : n \

sig n a ls);
consume;
if m = 0 then waii(delay)
forever
end;
begin (* m ain program )
n : 0;
s := 1;
delay
0;
cobegin
producer; consum er
coend
end.
H g . 4.9.

Nole the initial wait(delay) so that the consum er does not begin to
execute while the buffer is em pty. A lso, if the processes arc running at more
or less the sam e speed, n either is ever blocked on the sem aphore delay. This
is bccausc waii(delay) is executed only if the buffer is em ptied which need
not occur frequently. T he wait{delay) has been taken out of the M'ajy(j). . .
signal(s) bracket to avoid the previously discussed deadlock.
The new feature in the solution is the use of the local variable m to allow
the consum er to test the value of n as it was inside the criticial section, if the
statement in the consum er had read: if n = 0 then waii(delay) then the
following scenario shows that a superfluous signal can occur which leads to
consumption from an em pty buffer a flagrant breach o f safety. Define a
cycle of the producer (consum er) as execution o f the statem ents of the
producer (consum er) process from one occurrence o f the produce (consutne) to the next.
In the line m arked ( ) the consum er has skipped the wail in the state
ment if n s 0 then waii(delay) because even though it noted that n - 0 , the
producer has meanwhile increm ented n. The notation n - - 1 m eans that the
consumer has just consum ed an clem ent that is not there: - l * / ! = m - o u / s o
o u t- in + 1, i.e. the consum er has consum ed its (m + l)s t elem ent while the
producer has produced only in elem ents.

62

SEMAPHORES

A ction
Initially
Producer cycles
Consum er cxccutcs to consume
Producer cycles
C onsum er cycles
C onsum er cycles

CHAP. 4

n
0
1
0
I
0
-1

detay
0
1
0
1
If)
0

Using the local variable m , this bug will not occur (C heck!). Il is true
that (he consum er is m aking a decision based on stale inform ation: it could
be the case that, m eanw hile, the producer has produced a new element.
Then the consum er will execute waii{detay) and im m ediately pass it if the
producer has already signalled. The overhead of a superfluous wait is cer
tainly preferable to a violation of safety.

4 .6

TH E SLEEPING BARBER

There is another slight im provem ent that can be m ade lo this program . The
point of this discussion is not so much the im provem ent itself which may or
may not be significant. W hat is interesting is how a careful analysis o f the
synchronization requirem ent in a problem can lead to a different and better
solution. T he m oral of the story wilt be that before you decide to wait on a
sem aphore, you must clearly understand w hat you are waiting for.
Suppose we have the (com m on) case where the p ro d u cer and consum er
are running at roughly th e same speed. The scenario could be:
Producer: append-, signal; produce; . . . ; append; signal; produce; . . .
Consum er: consum e; . . . ; take; wait; consume; . . . ; take; wail; . . .
The producer always manages to append a new elem ent to the buffer and
signal during the consum ption o f the previous elem ent by the consumer.
This is not unreasonable since the processing to be done with the data is
assumed to be significant com pared with the buffer m anipulation and the
synchronization. The producer is always appending to an em pty buffer and
the consum er is always taking the last elem ent in the buffer; hence the
execution o fu g n a fa n d wait on every cycle. T hus even though the consum er
will never block o n the sem aphore, the processes nevertheless are executing
a large num ber o f calls to the sem aphore m echanism which does involve
non-negligible overhead.
In the program in Fig. 4.10, wc allow n to have the value - 1 which is lo
m ean that not only is Ihe buffer em piy but that the consum er has detected
this fact and is going to block until Ihe producer supplies fresh data.

THE SLEEPING BARHhK

SECT 4.S

63

program
var

sleepingbarber;
n\ integer,
j : ( binary ) sem aphore;
delay: ( binary ) sem aphore,
procedure producer;
begin
repeat
produce;
wait(s);
append;
n := + l ;
if n = 0 (hen signat(delay);
signal(s)
forever
end;
procedure consumer;
begin
repeat
H'Oif(j);
n :* / i - l ;
if n * - 1 then
begin
sig n a ls);
wait(delay);
W 'f l if ( j )

end;
take;
sig n a ls);
consum e
forever
end;
begin ( main program )
n := 0;
s := 1;
delay := 0;
cobegin
producer; consum er
coend
end.
F it- 4.10.

Before (he consum er w aits on delay it is carcful to release mutual


exclusion by signalling s to allow ihe producer to append a new elem ent to

64

SEMAPHORES

CHAP 4

th e buffer. T he stru ctu re o f the co n su m er shows an altern ativ e program m ing


co nstru ct to th e use of a local vuriablc us in the previous p rogram . T h e test on
n is m ade inside the critical section and the w aiting o u tsid e. Since Ihe test is
m ade inside, th ere is n o ch ance for th e p ro d u cer to change th e value o f n
b etw een the d ecrem en t o f n a n d th e test.
O nce th e delay is co m p leted we are careful to ask for th e re tu rn o f
m utual exclusion, hence th e e x tra
*,/f(.j). If wc try th e scen ario sk etch ed at
the beginning o f this section we find th a t even if th ere was o nly a single
elem en t in the b uffer, a fte r n : = n I the value o f /> will be zero so the
co nsu m er falls th ro u g h to co nsu m e. If the p ro d u cer can ap p e n d a new
c le m e n t fast en o u g h , the c o n su m er need never ex ecu te the waii(defay).

T h e tw o solu tio n s can be illu strated by th e m odel o f th e Sleeping


B arb er. A b a rb er has a tw o-room sh o p as show n in Fig. 4.11. O n e room with
the b arb er-ch air and a w aiting ro o m . T he th ree d o o rs show n a re : from the
stre e t to the w aiting ro o m , from the w aiting room to the ch air a n d from there
back to the stre et. T he d o o rs are assu m ed to be n arrow and allow a t m ost one
p erso n to p a ssa t a tim e (th e co m m o n m em ory a rb ite r). Let us now m odel the
stre a m o f cu sto m ers as a d ata e le m e n ts which th e b a rb e r m ust consum e"'.
T h e w aiting ro o m is the buffer. We now w rite a lg o rith m s fo r b o th th e b a rb er
a n d the custom ers.

SECT 4 6

TH E SLEEPING B A K b L K

65

A lgorithm 4.1
B arber W hen you have finished w ith a cu sto m er, show him out and
check th e w aiting room . If th ere is a cu sto m er, escori him to the chair;
otherw ise, go to sleep in th e chair.
C ustom er W hen you e n te r the w aiting room : if (here arc o th e r custom
ers (hen join them . If not, o p en ihe d o o r to see if (he b a rb e r is busy; if so,
do se ih e d o o r and w ail your (urn. If th e b a rb e r is a sle ep th e n w ake him.
In A lgorithm 4 . 1. if the rale at w hich cu sto m ers e n te r m atches the rale
of (he b a rb e r's w ork th e n ev ery c u sto m er will find h im self alo n e in the
wailing room and will vainly o p e n th e d o o r only (o find th e b a rb e r at work.
This co rresp o n d s to th e m ore obv io u s so lu tio n to th e p ro d u cer-co n su m er
problem .
Algorithm 4.2
B arber A s b efo re, ex cep t fbai if th e w ailing room is em p iy ihen g o to
sleep on th e bench in Ihe w ailing room .
C ustom er If th e re are o lh c r cu sto m e rs o r if th e w ailing ro o m is em pty
then wait y our tu rn . If (he b a rb e r is sleeping in th e w ailing ro o m th en wake
him.
In A lgorithm 4 .2 . a cu sto m er will w ail w ith o u t o p en in g Ihe d o o r to no
avail. E ventually the b a rb e r will finish w iih th e p rev io u s cu sto m er a n d invile
ihe new o n e in. O nly if Ihe b a rb e r is actually w ailing (sleep in g ) will a
custom er have to w ake him.
4 .6

THE BOUNDED BUFFER

An infinite buffer is not realistic. There are tw o basic tech n iq u e s lo bound


the size of a buffer. T h e first is ihe circular b u ffe r w h ere (he index o f the array
b is co m p u ted m o d u lo th e finite size o f th e array. T h a i is. th e d a ta is w rapped
around from the en d o f th e array to ils sta rt. T h e code for a circular buffer is
shown in fig 4.1 2 w here n is th e size o f the array b . S ee Pig. 4.13 to
un d erstand (he b o o lean cond itio n s (hat d efin e e m p ty a n d full buffers.
{* p ro d u cer )
produce',
wait u n til ( ( i n > - o u t ) and ( m - o u K n )
o r (in < o u t) an d ( o w l - m > l ) );
a ppend\
if in = n then in
1 else in := in + 1;
( co n su m er )
wail u ntil (in < > o u l)\
lak e;
if o u t ^ n then o u t : * 1 else o u t
o u t+ 1;
c o n su m e 1,

r
66

CHAP 4

SEMAPHORES

o ir rf

,1
<

-fife '*

IN |

OUT [

(b)
FI*. 4.13.

T here is always ai least one free space in b so that in = o u t can be


unambiguously identified as an empty buffer, not a full one.
T he o th er m ethod of bounding the size of buffers is to use two o r more
distinct buffers, usually of the sam e size. W hen one is filled by the producer it
is passed on to th e consum er which for its part prom ises to return the empty
buffers to the producer for rc*use. The circular buffer is very easy to program
and very thrifty of spacc since there is only one buffer elem ent o f overhead.
The multiple buffers need to be program m ed with some care since a mutual
exclusion mcchanism must be invoked during the transfer o f a buffer from
one proccss to another. M ultiple buffers can waste space. Suppose the
producer has filled b { but the consuincr still has a few elem ents left to
consum e in buffer b 2 (Fig. 4.14). T hen the producer must wait for the
consum er even though alm ost half of the overall buffer space is currently
empty.

P roducer

C onsum er

FI*. 4.14.

SECT. 4.6

THE BOUNDED BUf-HiR

A7

Multiple buffering is used in several situations. I /O equipm ent that uses


direct memory access may not have the ability 10 work with a circular buffer.
Typically such equipm ent uccepls com m ands that consist of an address and a
length of a mem ory segm ent into which the data is to be w ritten. This
translates nicely into a discrete buffer to be filled and passed to the program.
Another im portant use for multiple buffers is in com m unication systems
where the buffer requirem ents arc highly variable in tim e. R ather than
lllocatc a large circular buffer perm anently to each term inal, it is b etter to
construct a "p o o l" of many small buffers. An inactive term inal need not be
assigned any buffers; active term inals can be assigned a large num ber o f
buffers from the pool to be returned once the data transfer is com pleted.
To changc the producer-consum er problem to handle bounded buffers
is very simple. Just as the general sem aphore n counts the num ber of
elements of the buffer currently filled by d ata, the program in Fig. 4.15 uses
another sem aphore e lo count the num ber of em pty spaccsf W hen e reaches
zero there are no em pty spaces and the producer blocks until the consumer
removes some o f the data. T he solution has a pleasantly sym m etric form.
program
const
var

boundedbu/fer,
sizeofbuffer * . . . ;
s: (* binary *) sem aphore;
rt: semaphore-,
e: sem aphore;
procedure producer;
begin
repeat
produce;
wait(e)\
wa'u{s)\
append;
'sig n a lly ,
signal(/t)
forever
end;
procedure consum er,
begin
repeat
wau(n);
watt(sy,
take-,
signals)-,
signal(e)i
consum e
forever
end;

68

S tM A H H O R E S

C IIA P 4

beg in ( m a in p ro g ra m )
s : 1;

0;

e : size o fb u ffe r ;
co begin
p r o d u c e ; c o n su m e
coend
en d .
F ig . 4 .1 5 .

4 .7

E X E R C IS E S

4.1

Write several lest* until you thoroughly urkkrstand the difference between
Figs. 4.9 and 4.10.

4.2

Conway's Problem: Write a program to read 80-column cards and write them
as 125-character lines with the following changes. A fter every card image an
extra blank is inserted. Every adjacent pair o f asterisks is replaced by A.
O f course Conwayi problem can b e solved by a single sequential progiarn. However, it difficult to be sure that you have taken care o f all o f the
special cases such as pairs of asterisks at the end of a card and so on.
The problem has an elegant solution as three concurrcnt processes. One
process read reads the cards and passes characters through a one character
buffer to a process squash, read also passes the extra blank at Ihe end o f every
card image; squash, which knows nothing about 80-column cards, simply
looks for double asterisks and passes a stream o f modified characters to a
process p rim /m 'n /iak esth e characters and prinislhcm as 125-character lines

4.3 Write a program to solve Conway's problem with the additional requirem ent
that there be a 10-charactcr buffer betw een each pair of processes: read and
squtiih; squash and prim . Use m utual exclusion on the bounded buffer as
shown in Fig. 4 .IS.
4.4 In Fig. 4.12, simplify the condition in the producer's wait until clause.
4.5 W rite a scenario that shows that signal must be a primitive instruction and not
simply s := j + 1.
4.6 Add a sem aphore to program increment (Fig. 1.5) so that it always prints 40.
4.7

Write sonprogram so that merge is a third concurrent process.

4.8 Write a scenario showing lockout for the sem aphore solution to mutual
exclusion o f three processes.

EXERCISES

4.9

69

If you want to p a s a sem aphore as a param eter, should il be passed as a value


param eter or a reference param eter (v a r in Pascal), or does it not make any
difference? If you think that there is a difference, what happens if you make
the wrong choice?

4.10 Why is the program in Fig. 4.16 not a solulion to the problem of allowing at
most k processes into a critical region (using binary sem aphores only)?
(a) Show that if k - 2 and u = 4 it is possible to have d e la y -2 contrary to the
requirem ent that delay is a binary sem aphore.
(b) 'S how this even for 4 - 2 and /t - 3 .
program
const

m uluaiexctusion;
( num ber o f processes )
k . . . ; ( num ber in critical section )
var
count: integer;
j: ( binary ) semaphore',
delay: ( binary ) sem aphore;
procedure process (i: integer);
vttr m: integer,
begin
repeat
tvair(f);
count
count - 1 ;
m : count;
signal(s);
If m < = - 1 then wait(detay)\
crir,
k'<ur(j);
c o u n t: count + 1 ;
if count < - 0 Ihen ,iignal(dclay);
signal(s)
forever
end,
begin ( m ain program )
count : k;
S i - 1;
delay : = 0;
cobegin
process^ 1);
process{2)]
process(n)
coend
end.
Fig. 4.16.

4.11 (Kessels and M artin) A split binary sem aphore is a pair of binary sem aphores
* and y such that the formula 0 < x + y < - 1 is always true (i.e.. is an
invariant). Study the simulation (Fig. 4.1 7 ) of general sem ap h o res by the split
binary sem aphore.

70 SEMAPHORES

CHAP. 4

A program using ihe general sem aphore s should now declare s as an


integer, assign il an iniiial non-negative value and (hen use the procedures
gtnwait(s) and gensignal(s) below to simulate wait and Signal for a general
semaphore. The program must also declare and initialize global variables as
shown.

count: integer; ( initially 0 )


x: ( binary ) semaphore-, ( initially 1 )
y: ( binary ) sem aphore; ( initially 0 )
p ro c e d u re g en *<}//(v a r s: integer);
begia

wait(x);
while s < 0 do
begin

count : count +1;


signal(x); wait(y);
count : = count - 1;
if count ~ 0 th en signal(x) else iignal(y);
wait(x)
end;

s := s - 1
If count0 th e n rignal(x) else signal(y)
end;
p ro c e d u re gensignal(\ a r s: integer):
begin

wait(x);
f
j + I;
if c o u n t* 0 th e n signal(x) else signal(y)
end;
F ig . 4 .1 7 .

4.12 (M anna and Pnueli) W rite a concurrent program to com pute the binomial
coefficient (n * ) ( - 1 ) . . (/ -* + 1 ) / 1 ( 2 ) .. . (A), forO < - k < - n. Let
process P , multiply n then n - 1 then n - 2 and so on into a global variable x
while process P* multiplies I and 2 and so o n into a local variable^. Synchron
ize P , and P j so that P3 executes* : x div y w h en ^ , in fact, divides Jr. (Hint
it always divides j( j+ 1) . . . ( > + /- ! ) .)
4.1 3 *(Roussel) Write a concurrent program lo test if tw o binary trees have the

same leaves. T here will be three processes: P4, i - l , 2, will find the next leaf of
tree i. W hen two "n ex t leaves have been found, Pi will test them for
equality. The trees can be declared in Pascai-S as follows:
const

lype
v r

m axnodes= 40;
leftson= 0;
rightson * 1;
nodevaluem2;
n o d e - array [0 . . 2 ] of integer;
treetypea rra y f . . m uxnodes\ o f node;
tree: a rra y f 1 . . 2) o f trcetype.

EXERCISES

71

4.14 Study the im plem entation kit and describe the changes that must be made so
that the kit will catch misuse o f a sem aphore: tests and assignments (except in
the main program ). What changes must be made to differentiate general from
binary sem aphore?
4.15 (Parnas) Figure 4.18 is a solution to a pioblem called the Cigarette Smoker's
problem . Each one of the three agenn supplies two o f three possible
resources. T here are three sm okers each o f which needs exactly the pair of
resources supplied by one o f the agents. Study (and test) the solution and
answer the following questions.
(a) W hat is the function o f the helper processes?
(b) Explain how term ination o f the tasks is accomplished. What is the
purpose of t :*= 0 in procedure forcelerminaiion?
(c) Even though the program term inates, there arc certain bugs that may
occur on the final execution o f each process. Write examples for these
bugs and a b etter program that term inates correctly.
(d) Do you see a problem that might occur with the sem aphores 5(1). $(2),
j|4 f ? How can this problem be solved?
program cigarette-,
const trips 20;
var resource: array[ 1 . . 3] o f ( binary ) semaphore,
s: a rra y fl . . 6] of sem aphore;
m utex, sem : ( binary ) sem aphore;
/: integer,
finished: a rra y (l . . 3] o f boolean;
procedure forceierminaiion;
v ar i: integer;
begin
0;

for i : - 1 to 3 do signal(resource[i})\
for i : 1 to 6 do signal(s{i])
end;
procedure agent(n, res I, res2: integer);
var i: integer;
begin
for / :=* 1 to trips do
begin
H'a/r(frm);
signat(rcsourcc\resl]);
signal(resource[res2))\
w nteln( ' a g e n t' . /i)
end;
finisheti[n] : true
end;
procedure helper(n, increment: integer);
begin
repeat
wait(resource[n]);
wait(mutex);
t : / + increm ent;
signal(m utex)

72

SEMAPHORES

CHAP 4

until ftnithed[l\ and finished^2) and finished[2];


forcelerminution
end;
procedure smoker{n, index: integer);
b e g in

repeat

wait{s[index]);
i : 0;
writeln ('smoker',
signal(sem)
until finished[n J

n );

end,
begin ( main program )
for f : = I to 3 do resottrceii] 0;
for / : 1 to 6 do iff] : 0;
for t
I to 3 do fintshed[i) : false;

0;

mutex :
son : I ;

1;

cobcgln
ag<n(l.2.3); helper( 1.1); smoker(\,b);
ag</(2,l,3); helper{2,2); smokeri2.5);
gf/i(3.1.2); hetper[i.4)', smoker(3,3)
coend;

tvriiebi('smoking is dangerous)
ead
M g . 4.18.

MONITORS

5 .1

IN T R O D U C T IO N

W hile (he sem ap h o re is un eleg an t low level synchronization prim itive, an


o p eratin g system built o n sem ap h o re s alo n e is subject to d isaster if even one
o ccurrence o f a sem ap h o re o p e ra tio n is o m itted o r m istaken anyw here in the
system . We should like to have a m o re stru c tu re d syn ch ro n izatio n tool. In
seq u en tial program m ing, o n e can w rite p ro c e d u re s o u t o f sim ple statem en ts
and (hopefully) use th e p ro ced u res by e x te rn a l specification o nly by know
ing th e nam e an d p a ram e te rs o f the p ro ced u re. T he m o n ito r is designed lo
allow co ncurrency while retain in g the ad v an tag e o f a stru ctu re d construct.
T h e m o n ito r grew o u t o f tw o d istin ct ideas th a t are in com m on use. The
first is th e m onolithic m o n ito r u sed in c u rre n t o p e ra tin g system s. Most of
these system s are in effect single p ro g ram s th at centralize all critical func
tions. If a m essage m ust be passed from l \ to P j Ihen /*, passes it to "big
b ro th e r m o n ito r M w ith a req u est to forw ard it to P 2. o r a t least P , requests
perm ission to pass the m essage. Sim ilarly, reso u rce allo catio n is cen tralized
in M . Such m onitors are su p p o rte d by h ard w are facilities th a t en su re the
privileged position o f the m o n ito r: M ru n s in an u n in terru p ta b le m ode thus
g u aran teein g m utual exclusion; o nly M can access certain a re as o f m em ory;
only A/ can execute certain in stru ctio n s such as I / O instructions.
T h e m o nitors we study a re d ec e n tra liz e d versions o f th e m onolithic
m onitor. E ach m o n ito r will be e n tru ste d w ith a specific task a n d in tu rn it will
have its ow n privileged d a ta an d in stru ctio n s. T h u s if M , is th e o nly m onitor
that can access v ariable v, th en we a re e n su red o f m u tu al exclusion o f access
to v, becau se Af, will be u n in te rru p ta b le o r a s we say in th e ab stractio n : entry
to a m o n ito r by o n e process ex clu d es e n try by any o th e r process. In ad d itio n ,
since (he only processing th a t can be d o n e on v, is th e p rocessing prog
ram m ed in to th e m o n ito r, we are a ssu red th a t n o o th e r assig n m en ts o r tests
73

74

MONITORS

CHAP. 5

a rc accidently m ad e on v,. Wc can design d ifferen t m onitors (o r even


d ifferent instances o f th e sam e m o n ito r) fo r d ifferen t tasks. T h u s the system
is b o th m ore efficient bccause execution o f d istinct m o n ito rs can be done
c o n cu rren tly , a n d m o re robust because a change in o n e m o n ito r cannot
su rrep titio u sly ch an g e a variable in a n o th e r m o n ito r.
T he o th e r id ea b eh in d m onitors is th at o f stru c tu rin g d ata a n d stru c tu r
ing accesses to d a ta in a program m ing language. Pascal was the first language
specifically d esig n ed to stru ctu re d ata by typing. T h e p u rpose o f d a ta typing
is lo p rev en t in d iscrim in ate mixing o f d ata th at have n o p urpose bein g mixed
e v en (hough th eir re p re se n tatio n may be iden tical. F o r ex am p le, even
th o u g h it m ight occasionally be co n v en ien t to ad d a n u m b e r to a character
(a n d P L /I will be happy to d o so), Pascal tak es th e view th a t such a statem en t
is alm ost certain ly in e rro r an d refuses to com pile ih e sta te m e n t. If this is
w hat you really w ant th en you must placate the com piler by w riting an
explicit conversion.
W hile typing is successful as far as it goes, il applies only to the data
itself. T h ere is no way in Pascal lo d efine a type w hich consists o f integers
th a t may only be a d d ed o r su b tracted . T h e re is n o way o f asking th e com piler
to flag a m ultiplication as u n reaso n ab le (in an acco u n tin g system , it might
n o t m ake sense to m ultiply tw o sum s o f money-o nly to ad d and su b tract
them or 10 m ultiply a sum by an in terest rate o r a tim e p erio d ). T h e id ea of
typing by th e o p e ra tio n s p erfo rm ed is found in th e language Sim ula 67. A
class in Sim ula 67 is a d a ta d ecla ratio n to g e th e r w ilh a set o f p ro ced u res
which d efine the only legal o p e ra tio n s th a t may be p erfo rm ed o n the data.
T he Sim ula class has b e e n com bined w ith the Pascal d a ta type in th e Ada
p a ckage featu re w hich p rovides a carcfully d esig n ed m echanism th a t allows
the p ro g ra m m e r to stru c tu re his pro g ram to reflect his know ledge o f the
p ro p ertie s o f the d a ta .
A m o n ito r is a class th a t can be e x ecu ted in tu rn by several processes.
F o r ex am p le, even (h ough th e b u ffer is an a rray , th e re is n o reaso n ab le thing
to d o w ith a b u ffer ex cep t to a p p en d a new clem en t o r ex tract an old o n e . A
ran d o m access to a b u ffer a rra y is p ro b ab ly a m istake. T o so rt th e elem en ts of
a b u ffer sim ply c o n trad icts (Ik d efin itio n o f a b u ffer as an a re a o f m em ory
from w hich d a ta is e x tra c te d in ihe sam e o rd e r th a t it was a p p e n d e d . In the
m o n ito r n o ta tio n , o n c e the b u ffer m o n ito r has b een w ritten , th e re is no way
to even ex p ress such a m istake. T h e co m p iler will refuse any access by a
proccss to a b u ffer except th ro u g h p ro c e d u res a p p e n d and lake.
In th is c h a p te r w e fo rm ally d efine th e m o n ito r as a program m ing
prim itive and give ex am p les of its use. We show how to im p lem en t m onitors
on a system w ith sem ap h o res. M onitors have been used very successfully
in co n c u rre n t p ro g ram m in g languages such as C o n cu rren t Pascal and
C S P /k .

SbCI J 2

D E F IN IT IO N O r M O N II OKS

7S

$.2 D E F IN ITIO N OF M O N ITO R S

A m o n ito r is w ritten as a se t o f (glo b al) v ariable d ecla ra tio n s follow ed by a


set o f p ro ced u res (w hich may be p a ra m e terize d ). T he m o n ito r has a body
(begin . . en d ) w hich is a seq u en ce o f sta te m e n ts th a t is ex ecu ted immcdi*
ately w hen the pro g ram is in itiated . T h e bod y is used to give initial values lo
the m o n ito r variables. T h e re a fte r, the m o n ito r exists o nly as a package of
data and p rocedures.
T h e variables in th e m o n ito r a re dircctly accessible only w ithin the
m onitor p rocedures. C om m u n icatio n b etw een a m o n ito r and th e outside
w orld is through th e p a ram e te rs o f Ihc p ro ced u res. In the usual vocabulary
of program m ing languages, th e scope o f the m o n ito r v ariab les is the m onitor
(* set o f m o n ito r p ro ced u res). Since th e m o n ito r is a static o b ject: variable
declarations a n d p ro ced u re d eclaratio n s, the o nly w ay to execute the
m onitor is fo r a process to call a m o n ito r p ro ced u re.
p ro g ram producerconsum er;
const
size o fb u ffe r = . .
m o n ito r b o u n d ed b u ffer;
b : a rra y [0 . . sizto fb u ffe r] o f integer,
in , out: integer;
n: integer;
p ro ced u re a p p en d (v: integer);
begin
If n - s ize o fb u ffe r+ 1 ( the b u ffe r is fu l l )
then w ait u n til n o t fu ll" ,
: v;
in : in + 1 ;
if in = size o fb u ffe r + 1 then in : = 0;
n : n + 1;
"sig n a l that the b u ffe r is n o t e m p ty
end;
p ro ced u re take (v a r v: integer);
begin
if n 0 ( th e b u ffe r is e m p ty )
then "w a it until n o t em p ty ";
v : b{out]\
o u t : = o u t + 1;
if o u t - s ize o fb u ffe r -*-1 th en o u t : 0 ;
n
tt - 1;
signal that the b u ffe r is n o t f u l t '
end;

76

MONITORS

CHAP 5

begin (* m onitor b o d y )
in := 0;
out
0;
n := 0
end;
( end o f m onitor boundedbuffer )
procedure producer,
var
v: integer;
begin
repeat
produce (v);
append (v)
forever
end;
procedure consumer',
var
v. integer;
begin
repeat
take (v);
consum e (v)
forever
end;
begin ( main program )
cobegin
producer; consum er
coend
end
Fig. S.l.

Figure 5.1 shows a solution to the producer-consum er problem using a


bounded buffer. It consists o f a program producerconsumer which con
tains a m onitorboundedbufferand two concurrent processes producer
and consumer. W hen the program is initialed, the m onitor body is first
executed. T hen ihe main program is executed which causes the initiation of
the concurrent processes. The m onitor procedures a ppend and take sit
passively until called from a proccss.
If a producer wishes to append an elem ent v to the buffer, all it need do
is call the m onitor procedure append(v). Similarly, the consum er can call
take(y) to obtain the next elem ent. Wc require that entry to a m onitor be
done under m utual exclusion. T hus either the producer is executing append
o r the consum er is executing take (or neither). T hen the o perations on the
variable n by both processes d o not interfere with each other.
This solution has certain advantages over the unstructured sem aphore
solution aside ftom th e m ere fact of th e protection of the variables from

SE C f. 5 2

DEFINITION O f MONITORS

77

outside interference and (he structuring of Ihe acccsscs. Since the mutual
exclusion is autom atically guaranteed by the m onitor, there is no counter
part to a bug caused by om itting a signal to release m utual exclusion. If you
forget the end statem ent of m onitor procedure, lhal is a compilation error
just as it would be in an ordinary program . In addition, the wailing and
signalling is program m ed within the m onitor. T he users o f the m onitor need
only call a procedure. Thus once a m onitor is correct, it will be correct for
every instance used by every set o f processes. In the case o f the unstructured
sem aphore, the correctness depends upon sem aphore o perations that must
be explicitly program m ed into every process.
For synchronization we need some so n o f w ail-signal commands.
The sem aphore com m ands served two purposes. One is to provide a
bfock-wakeup facility and the o th e r to maintain a count. Since (he counts
can now be explicitly contained as integer variables in the protected monitor
data, it is sufficient to provide a block-w akeup facility. Just as several
sem aphores may be needed in one program , so one m onitor may need
several w ait-signal pairs. We define a new type o f variable called a condition
variable. If c is a condition variable then there are two com m ands that can be
applied to c: wuit(c) and sigrtal(c) (these will now be defined for monitors;
they are nol to be confused with the com m ands of the sam e name for
sem aphoresalternatively call the sem aphore com m ands P and V):
wait(c)

The calling process is blocked and is entered on a queue of pro


cesses blockcd on this condition, i.e. have also executed hw /fc)
comm ands. Unlike sem aphores we assume that the queues are
FIFO.
signa/(c) If the queue for c is not em pty then wake the first process on the
queue.
Executing signal(c) when there are no processes waiting in the queue fo re is
a no-opcration and leaves no traces (again unlike the sem aphore). The
commands may be w orded: 1 am waiting for c to occur" and I am
signalling that c has occurred". O f course it is the responsibility o f the
monitor program m er to ensure that c has occurred when th c a g n a / is issued.
The execution of tva//(c) releases the m utual exclusion o n the entry to
the m onitor. T hat this must be true is obvious. If P, is blocked waiting fo re to
occur, some process P2 must d o the signalling. If P, is not assum ed to release
the m utual exclusion then P2can never en te r and the system is deadlocked. If
we model the m onitor as an igloo, Ihe blocked processes can be considered
to be in a deep-freezer in the basem ent. They do not take up room in the
igloo s o o th e r processescan move around. O f course when a process signals,
we must arrange either for the signalling process to leave the igloo immedi
ately or for the blocked process to wait tem porarily until the signalling
process does leave. T hisensures th at there isonly one process at a time in the
igloo.

78

MONITORS

C H A f. 5

In the m eantim e wc make ihe restriction that there be at most one signal
per procedure and that it be the last statem ent in Ihe procedure. T hus (he
signalling process leaves the m onitor immediately after the signal. This
evades the question raised in ihe last paragraph; we shall return to it in the
last section.
Im mediate Resum ption Requirement Let a process execute signat(c)
and suppose that there are processes in the queue fo re as well as processes
waiting to en ter the m onitor by a norm al procedure call. T hen the process on
the head o f the queue for c is the next process to e n te r the m onitor; in
particular it has priority over the processes which are trying to e n te r the
m onitor by procedure call,
Lei us see why this requirem ent is needed. Suppose that process P x has
noted that the condition is fulfilled and signals. If a proccss P j is allowed to
en ter the m onitor (by a procedure call) before a proccss P2 (which is waiting
on condition c), then conceivably
could cause c to become false. For
example, if Pt is a producer signalling buffer*not*empty and b o th P2 and Pt
arc consum ers, ihen it would be fatal if the interloper consum ed the single
d ata elem ent before the aw akened process Pt is allowed to proceed. Under
the Im m ediate Resum ption R equirem ent, how ever. P2 can assume that
w hatever P t checked im mediately before issuing the signal is still irue
because no interloper could falsify it betw een the signal and the resum ption
o f the first blocked process.
Finally, to com plete the bounded buffer exam ple, we must declare two
conditions in the variable declaration part of the monitor:
notem pty, notfull: condition',
and replace the phrases in quotes by th e comm ands:
wail(noifull)
signal(notempty)
wait(notempty)
stgnal(notfuH),
respectively.

5 .3

S IM U L A T IO N OF TH E S E M A P H O R E

The second exam ple we describe is th e im plem entation o f a binary


sem aphore by a m onitor. This is im portant theoretically since it shows thal
we have not lost any expressive pow er in th e transition from sem aphores to
m onitors. Practically, systems based on m onitors are relatively com m on. If
you have a ready-m ade sem aphore algorithm you might want to run it as is
on the m onitor-based system.

sen j j
i

s im u la t io n

of me

sem ap h o re

79

The m onitor (Fig. 5.2) will use a boolcun variable busy which will
i indicate w heiher or not a wail o peration has been com pleted on ihe
' semaphore (and hence that the critical section is busy ). If the sem aphore is
busy, we must wait until it is not busy so according lo ihe wording of the
! monitor operations we might as well call the condition noibusy. The iwo
j procedures will be called P and V to avoid confusion here with the monitor
j operations.
program
nutiualexclusion;
m onitor semaphoresimulation\
var
busy: boolean;
notbusy: condition',
procedure P\
begin
if busy then wait(noibusy)\
busy : true
end;
procedure V\
begin
busy : * fa lse ;
signal(notbusy)
end;
begin ( m onitor )
busy :m false
end,
procedure
begin
repeat
P.
crit 1;
V',
rem \
forever
end;
procedure p }\
begin
repeat
P.
crii2;
V\
re m l
forever
end;

80

CHAP 5

MONITORS

begin (* main program *)


cobegin
p1;p2
coend
end.
n g . 5.2-

Let us check that ihe various requirem ents are fulfilled. T here is at most
one signal in every procedure and when it docs occur, il is the last statement
in V. If a signal is executed when there are blockcd processes then it is
executed when busy is false; hence, a blocked proccss which is awakened
need not check that fcujy is now false and can proceed to set it true. Note how
Ihc m utual exclusion of the m onitor entry prevents the bugs we once had
when two processes simultaneously checked a variable such as J>usy and then
set it.
T his im plem entation of a sem aphore is the strongest implementation
possible because o f the FIFO assum ption on the queue o f processes blockcd
o n u condition. T he sem aphore definition does not require FIFO but it
certainly does not forbid il as a scheduling strategy. Thus any semaphore
algorithm proved correct under a w eaker assumption is still correctA condition variable does not have a value in the usual sense of the word
and hence no initialization is needed. To be more precise. every condition
variable is implicitly initialized to the empty queue of processes blockcd on
it.
It seems that we need a different m onitor for each sem aphore In
practice, systems using m onitors allow one to declare m ultiple instances and
even param eterized sets o f m onitors. If the m onitor procedures are written
as re-entrant* procedures (Pascal procedures are autom atically re-entrant),
it is sufficient lo allocate new instances o f the global variables for each
instance o f a monitor. In the case of the sem aphore m onitor, this means a
new boolean variable busy and a new queue for the condition noibusy. But
that is exactly the am ount of storage needed for a sem aphore under ihe
direct definition!
5 .4

THE REA DERS A N D W RITERS PROBLEM

A generalization o f the m utual exclusion problem is the problem of the


readers and w riters. The prototype for the abstract problem is an on-line
t A procedure is called rrtntrant if in code can be used simultaneously by several
processes. This ({accomplished by writing pure code: code which is not self-mudifyiag
and which accedes utl its data indirectly from an address usually kept in u register.
Thus by merely changing the address in the register and remembering the current
location of the program counter, the same code can be switched among several
programs In Pascal, procedures are always pure code and data is accessed by staci
pointers Hence by changing the stack pointers, a procedure can be forced to work on a
different set of data.

SECT 3 4

THE READERS AN D WRITERS PROBl.EM

81

transaction system such as a banking system not requiring m utual exclusion


among several processes which only read th e data. H owever, an update or
any operation that writes d ata must be considered to be a critical scclion lo
avoid the type of bugs which should be thoroughly fam iliar by now. A
monitor lo solve this problem is given in Fig. 5.3.

program
reudersandwriters;
monitor readwrite,
var
readers', integer,
writing: boolean',
o kf oread, oktowrite: condition,
procedure startreud;
begin
If writing o r nonem pty (oktow rite)
then wait(ok(oread)\
readers :* readers+ 1;
signal(oktoread)
end;
procedure endread;
begin
readers : r e a d e r s -1;
if readers 0 then signal(oktowrite)
end;
procedure startwrite;
begin
if readers < > 0 o r writing
then wail(t>ktowrite)',
writing : true
end;
procedure endwrite;
begin
writing : false;
if nonem pty{oktoread)
then signal(oktoread)
else signal(oktowrite)
end,
begin (* m onitor *)
readers := 0;
writing : = false
end;

8-1

CHAP J

MONITORS

When no proccss is currently executing a m onitor procedure, th e fol


lowing formulae are true (i.e. the formulae arc invariant outside the
monitor).
(a)
(b)
(c)
(d)

R readers-,
W > 0 if and only if writing * irue;
nonem pty(oktoread) only if (writing or nonem ply(ok to write)) ',
nonem piy(oktow rite) only if (readers * 0 o r writing);

Each of these statem ents is initially true and it must be checked (Excrcise 5.7
(a)) that, if a statem ent is true upon entry into a m onitor procedure, it is still
true when the process exits the procedure.
Points to rem em ber are: execution o f a wait is also u way of exiting a
m onitor procedure; if a statem ent is true im mediately before the execution
of a signal then, by the im m ediate resum ption of an aw akened proccss, the
truth o f ihc statem ent is Irunsfered lo the resum ed process.
The basic safety property required of a solution to the problem o f the
readers and the w riters will be proven if we can show that the following
formula I is invariant:
If R > 0 then VK= 0 and if W

> 0

then

I and R = 0).

In words: if there arc (active) readers then there are no writers, and if there
are (active) writers (hen there is only one
w riter and no readers.
I is initially true since R * W = 0. We show th at I is always true by
showing that any attem pt to describe an execution sequence which falsifies I
is unsuccessful.
1. Suppose R > 0 and ^ = 0 (so that I is true) jtnd then I is falsified by some
proccss starting to write (so W will becom e 1).
By (a), R > 0 implies readers > 0 so the process that wishes to write will
watt in procedure startwrite. The only way (his scenaiio could falsify I is if a
signal(oktowriic) occurs. T he signal in ertdread is executed only if re a d e rs-0,
contrary to assumption. The signal in endwrite will also not be executed sincc
there are no w riters by the assumption
2. Suppose R**Q and W > 0 and then som e process starts reading so that
I,
falsifying I.
W > 0 im plies writing true by (b), so any proccss executing startread
will wait on oktoread. Since R - 0, there arc no readcrs so signal(uktoread) is
not executed in endread. Now I is assumed true so W > 0 implies W= I . Thus
executing signal(oktoread) in endwrite upon term ination of writing occurs
when ^ = 0 contradicting the assum ption of this scenario.
3. IV= I . R - 0 and then some process starts writing to falsify the second
clause of I.

SKCT. S 5

PROVING PROPERTIES OF MONITORS

85

T his is im possible by Ihe code in startwrite. I he only signal possible is


(he one from endwrite, but then /?= W '0 so I is nol falsified.
The liveness properties of the solution are: if P wishes to read (or write)
then eventually il will be allowed to d o so. Lei us prove ihe liveness of
reading and leave the proof for writing as an exercisc (see Excrcise 5.7 (b)).
If P wishes to read then, it must successfully com plete the execution of
startreud. If it cannot do so, it must becom e enqueued indefinitely on
oktoread. Wc prove that oktoread is signalled indefinitly often. Since Ihe
queue is F IFO and the num ber of processes Px . . . , P k ahead of P is finite,
eventually P must be aw akened and allowed lo read.
By (c) above, either w ritings true o r nonem pty(oktow rite). If writing
true ihen by (b), W > 0 so som e process Q is writing.
(i) (Q is writing) implies eventually (Q executes endwrite) by th e assump
tion on critical sections that writing term inates.
(ii) (Q is in endwrite) implies eventually (Q executes signal(oktoread)), by
the assum ption that P is indefinitely enqueued on oktoread so that
nonem pty(oktoread) is true.
(iii) ( Q e x e cu tes sig n a l(o kto re a d )) im plies ev e n tu a lly ( P | ex ecu tes
signa!(oktoread)), by the im m ediate resum ption of a waiting process
and the code in startread.
(iv) (P , e x e c u te s sig n a l(o kto re a d )) im p lies e v e n tu a lly ( P 3 ex ec u te s
signa/(oktoread)). by im m ediate resum ption and Ihe code in startread.
(v) (Q is writing) implies eventually (Pk executes signal(oktoread)), by
(i)-(iv) and induction.
It easily follows that eventually P m ust successfully com plete startread and
commence reading.
Suppose now that writtngmfalse but nonem pty(oktow rite) true. By (d)
and the assum ption that w riting-false, rea d ers* Oand thus by (a) there musi
be P . . . , P* currently reading.
(i) ( P .............Pt arc all the reading processes) implies eventually ((some P,
executes endread) and ( P ,..........P,_t , P&,............. P* are all the reading
processes)), since reading term inates and nonem pty{oktow rite) blocks
new readers.
(ii) ( P ,, . . . , Pk are all the reading processes) implies eventually ((some Pt
executes endread) and (there are no reading processes)), by induction.
(iii) ( P ,............P* are all the reading processes) implies eventually (P,
executes signal(oktow rite) and then w ritin g -tru e), using im mediate
resum ption and nonem pty(o kto w rite)-tru e.
This reduccs to cite previous ease for which we have already shown liveness.

86

6.6

MONITORS

CHAP. 3

THE SIM ULATIO N OF MONITORS BY SEMAPHORES

Wc now give an algorithm for transform ing a program using m onitors into i
program that uses sem aphores. This will show that m onitors are no more
powerful than sem aphores and hence (hat the decision to use m onitors can
be m ade solely on the basis of (heir contribution to the clarity and reliability
of the resulting system. This transform ation is conccrncd only with the
dynamic behavior o f the concurrent system. The static protection o f monitor
variables should still be im plem ented, if possible, by n facility such as the
Simula 67 class o r the A da package.
The m utual exclusion o f the m onitor procedures is easily sim ulated by a
binary sem aphore. T h ere will be a sem aphore s (initially 1) for each different
m onitor and each procedure o f a m onitor will comm ence with wail(s) and
term inate with signal(s) just as wc solved the critical section problem with
sem aphores. For each condition cond wc need an integer variable condcount
to count the num ber o f waiting processes and a binary sem aphore condsem
to actually block the waiting processes. The iniiial value of condcount is 0.
T h at of condsem is also 0 because a proccss executing the m onitor wait
always blocks. Each com m and waii(cond) o f the m onitor is now coded:
c o n d c o u n t: condcount + 1 ;
sig n a ls);
w ait(condsem );
c o n d c o u n t: co n d co u n t- 1 ;
The signal on Ihc sem aphore s is to release the m utual exclusion on th e entry
to the m onitor in o rd er to allow o th e r processes to en ter, including (hope
fully) one which will eventually signal.
R em em ber that we have restricted the signal(cond) to be the last
com m and o f a procedure. H ence (he release o f a blockcd proccss from tlte
sem aphore condsem can be com bined with the release of the m utual exclu
sion in the following code:
if condcount > 0 then signal (condsem ) else signal(s)
This im plem ents o u r restriction th at, if there are processes waiting on a
condition, they have priority over processes waiting at the m onitor entry
points. T he blocked processes are waiting on condsem ; the processes wishing
(o en te r are wailing on s. So only if there are no blockcd processes (condcount~Q ) is th e m onitor entry freed. N ote that the signalling proccss must
have passed a wait(s) sem aphore upon entry, H iu s the aw akened process
inherits the outstanding m utual exclusion from the signalling process. The
debt is m ade good when (he aw akened process term inates and executes
signal(s). O f course it could avoid this by aw akening still a n o th er proccss.

SECT. S t.

1 HE S IM U l.A liO N Oh MONITORS BY SUMAPHORbS

87

Il
is interesting th at. according to o ur definition of sem aphores, the
value of the sem aphore condsem is never 1. It is initially 0 and signal(condsem) isonlycxccuted if some process is w aitingon cow/sem . Thus co/ufom is
never increm ented.
The only feature of the m onitor that we cannot im plem ent is Ihc FIFO
assumption on the queue because (he sem aphores are nol FIFO.
In Fig. 5.4, we show how this translation can be carried oul for the
producer-consum er program in Fig. S .l.
program producerconsumer;
const
sizeofbuffer . . .
var
b: arrayfO . . sizeofbuffer) of integer;
in, our. integer;
n: integer,;
5: ( binary ) sem aphore; ( fo r m utual exclusion )
notem ptysem , noifullsem: ( binary ) semaphore;
notem plycount, notfullcount: integer;
procedure append (y; integer);
begin
H'ajf(i);
If n sizeofbuffer+ 1 then
begin
notem plycount := notemplycount-* I;
signal(s),
n>aii(noiemptyseniy,
notem plycount := notem plycount 1
end;
if notfullcount > 0 then signal(noifullsem)
else sig n a ls)
end;
procedure take(va r v: integer);
begin
if n = 0 then
begin
n o tfu llc o u n t: * noifullcount+ I ;
signal(s)
w aii(noifuthem )\
notfullcount : = n o tfu llc o u n t-\ \
end;
if notem ptycount > 0 then signai(notem ptysem )
else sig n a ls)
end;

88

MONITORS

CHAP J

procedure producer',
procedure consumer\
begin ( m ain program )
in : * 0; o u l 0; n : 0;
s : I;
n o te m p ty c o u n t: 0 ; nolfulicounl : * 0;
noiem ptysem
0; noifullsem : = 0;
cobegin
producer, consum er
coend

5 .7

U N R E STR IC TE D S IG N A L S

If wc allow signal(c) to appear anyw here in a m onitor procedure then wc


face the following dilemma. A prim ary advantage of the m onitor is the
im m ediate resum ption of a signalled process while the condition is guaran
teed. T his saves needless looping and re-testing th a t is characteristic of
sem aphore algorithm s. Thus wc cannot let a signalling process continue after
the signal because it might change ihe condition o r execute another signal
causing a third process to be immediately resumed.
On i he o th er hand, the signalling process is not waiting for anything so it
seem s a pity lo block it. N evertheless, im m ediate resum ption is so central to
m onitor program m ing that we retain it and instead block the signalling
process. H owever, the signalling process is kept close at hand so that when
(he aw akened process releases the m onitor (by exiting o r executing another
wait) it has priority over o th er processes wishing to en ter. O f course, nothing
prevents the aw akened proccss itself from signalling and thus joining the
previous signaller.
In the igloo model (see Fig. 5.5), the igloo has only room for one process
at a tim e. It has d eep freezers in the basem ent for processes to wail on
conditions. We add a closet with a spring loaded door.
E ntering and exiling the igloo is on the basis of m utual exclusionone
at a time. If a process waits Ihen it enters the freezer for llte appropriate
condition. If a process signals, it invites a frozen proccss to e n te r the igloo.
The signalling process itself enters the closet so as not to interfere with the
privacy of the aw akened proccss. W hen the igloo is cleared, e ith er because
the process has exited o r entered another freezer, the spring-loaded door
flies open, thrusting the signaller into th e igloo before a new process can
enter. If aw akened processes signal, they will be stacked in the ciosct on top

s e c t 3 .7

UNRESTRICTED SfGNAI.S

89

<1

of (he previous processes.


We can now appreciate the simplification obtained by restricting the
signal to being the last statem ent in a procedure. In the more general model,
the signaller would em erge from ihe closci only to exit immediately. The
signaller might just as well exit im mediately after the signal and we need not
build the eloset into the igloo.
The sim ulation of the unrestricted m onitor by sem aphores is more
complicated (Pig. S.6). We need a new variable urgent and a new sem aphore
usem to count and block the signallers. In the sim ulation o f wait{cond) and
exit, the release of the m onitor now checks urgent to sec if there are waiting
signallers, urgent > 0 will signify that there is som e waiting signaller that is
demanding to be released (by signal(usem )) before any new processes can he
allowed lo enter (by jign a/(j)).
In the sim ulation o f sigttaI(co/td), condcount > 0 signifies that tin:re is in
fact a proccss waiting for this condition. The process is aw akened (by
signal(condscm)) and then the signaller suspends itself (by waii(uscm)).
entry: wait(s);
wait(cond): condcount ;= cond co u n t+ 1;
if urgent > 0
( / / wailing signallers )
then signal(usem )
( free a signaller )
else signal(s)\
( la a new process in )
wait(condsem );
condcount
condcount\;

'9 0

MONITORS

CHAP. $

s< naf(con4): urgent : urgent + 1",


if co n d co u n t > 0 (hen
begin
signai(condsem );
w ait(usem )
end;
urgent := u r g e n t- 1;
e x i t : if urgent > 0
then signal(usem )
else sig n a ls);

(* i f so m eo n e is wailing )
( lei h im in )
( su sp en d y o u rs e lf *)

(* i f a waiting signaller )
( fre e a signaller )
( let in a n ew process )

r i g . 5.6.

5 .8

E X E R C IS E S

5.1

Suppose that signals are not restricted but that some particular signal is in fact
the last statement in its procedure. Code a simplification to simulation of
monitors by semaphores for this case.

5.2

Show that even if ihc implementation of the semaphore is FIFO, the simula
tion of the monitor by semaphores is not.

5.3

Translate the monitor solution to the problem of the readers and the writcre
(Fig. 5.3) to a semaphore solution.

5.4

(Couitois et at.) Fig 5.7 is a solution to the problem of (he readers and the
writers using semaphores- It iscasy to see that/-counts the number of readers,
s guarantees mutual exclusion to variable r and wsem guarantees mutual
exclusion to writing.
(a) Discuss the priority scheme of this solution.
(b) Suppose that you have a FIFO implementation o f semaphores. How
would that uffcci the answer?
program
var

readersandwriters;
r. integer;
S,
wsem: ( binary ) semaphore;
procedure readprocess;
b tti
repeat
r :* r + 1 ; if r - l then wait(wsem)\
signals);
readthedata-,
wait{s)\
r
r - 1 ; if /-() then stghal(wsem);
signal(s)
fortver
end;

#
EXERCISES

91

procedure writeprocess;
begin
repeat
wair(tvsem);
writethedata;
signal(wsem)
forever
end;
begin (* main program )
r := 0;
t : 1;
wsem : * 1;
cobegin
readprocess; ( . . . )
wnteprocess; ( . . . )
coend
end.
Fig. 5.7.
5.5 (C burtoisera/.JThe solution in Fig. 5.8 usesa somewhat symmetrical codc for
both the readers and Ihe writers except that in the writer, wsem is used to
guarantee mutual exclusion m the execution of the write itself while, in the
reader, rsem is used only by the writer to prevent readers from entering the
critical section bracketed by J |.
(a) Discuss (he priority scheme of this solution.
(b) How would the solution change if ihe semaphores were FIFO?
(c) What would happen if s 3 were omitted? (//mi/ Show that ensures that
rsem -0 implies that there is cxacily one process waiting tor signal(rsem)).
program readertandwriters;
var
r,w. integer;
5,, j j , fj: ( binary ) semaphore;
wsem, rsem: ( binary ) semaphore;
procedure readprocess;
begin
repeal
woit(rsem);
wait(s,);
r :* r+ I;
I f r * I ihen waii(w$em);
signat(s,)\
signat{rstm)\
signal(s3y,
readihedaia;
wu'r(s,);
r .* r - i ;
if r=Q then signal(wsem);
signals t)
forever
end;

92

MONITORS

CM A^

procedure wriieprocw,

.j

b tg in

i]

repeat

*wV(f2);
h> : w v J ; |f >tej then tvail(rsem);
signaUst);
wu(*vsem);
wriiethedata-,
signal(wsem);
w := m>- ); if *v= 0 then signal(r$em)i
Signal(s2)
forever
end;
begin ( main program )
r :* 0 ; k- ;= 0 ;

jj : I; *i :* I;

:* I;

rsem : = ]; wsem : I ,
cobegi*
readprocesf, ( * . . . )
wrueproccsi, ( . . . )
coend
end
Pis . .<-8.
5.6

For each of the priority schemes (Section S.4 and Exercises 5-4 and 5 5) try lo
think of an application in which (hat schcme is Ihc reasonable one 10 requirt.

5.7

Complete llic semi-formal proof of the solution to Ihc problem of the readers
and the writers.
(a ) Prove the invariants (a)-(d).
(b) Prove the liveness of writing.
(c) 'Prove tlte following statement 5 which expresses the priority scheme
claimed for the solution.
S: If {Q enters uartvtrite before P enters uariread) then (Q writes before P
reads).
Hint How to piove precedences:
Let p and q be any two properties of programs. Then (p before q) is equivalent
lo (p is now true) or lq is now false and after executing a slep o f ihe program
Ihen (p before q)). Similarly, the negation of (/> before q) is equivalent to (p is
now false) and (4 is now true or after a step then ip before q) is false).
Show (haI the negation of S is inductive, that is, if S is assumed false then after
executing b step of the program 5 must still be false- Deduce that (Q enters
stanwr'tte) but never (Q writes) (hus contradicting Ihe liveness of writing
shown in (b).

t
I

THE ADA RENDEZVOUS

e .l

IN T R O D U C T IO N

The sem aphore and the m onitor arc centralized facilities. A process cxcculing a m onitor procedure has access to the single copy of the monitor
Jvariables and thus there must be an arb iter to enforce m utual exclusion.
While these requirem ents arc natural in a single com puter (o r any common
memory system ), they are difficult to im plem ent in a distributed system. By a
distributed system we m ean a set of totally independent com puters whose
only connection is by sending and receiving messages. T h ere may be no
synchronization betw een sending and receiving a message. Messages may
"pass cach oilier in transit. W hat we need is som e sort of self-enforcing
protocol. A proccss will decide to wait on its own initiative as in the busy wait
algorithms of C hapter 3.
In those algorithm s, each process agrees to enter a while loop if it needs
to block itself. Each proccss decides by ilself w hen to leave. This contrasts
with Ihe sem aphore and the m onitor signals which are req u ired lo wake
another process.
L am port's bakery algorithm s discussed in the exercises of C hapter 3 are
designed for distributed systems. Each process writes only into a single local
variable. I he lesl n, > 2 in proccss Pt can be interpreted as follows. Send a
request to process
to read the value of
Wait until P 2 replies. Compare
ihe received value with (he cu rrcn t value o f (he local variable
Each process needs 10 be augm ented with polling statem ents (hal
periodically search for requests for data values from o th er processes. A lter
natively (his can be done by interrupts. T he receipt o f a message from the
communica(ion line will trigger an interrupt in the receiving process. This
process will then identify (he message and route it for appropriate action.
If wc exam ine (he protocol suggested in the Iasi paragraph we find that
the essential idea is (he transfer o f inform ation at a predeterm ined point in
each process. We call (his a rendezvous of the two processes. T he essencc of
93

94

THE A D A RENDEZVOUS

C H A P .*.

any rendezvous is th at the parly which arrives earlier is required to wait. The
alternative to a rendezvous is a buffered message system but aside from
questions as to the size and num ber o f buffers, we now have (he question of
who ow ns the buffers.
In classical system s the buffers belong to the "sy stem ", but in a distri
buted system, we do not want to single out any process as th e boss. If that is
what we want th en the m onitor formalism is sufficient. Since message
passing systems are an obvious task for concurrent program m ing, we prefer
to base the program s o n an independent primitive such as a rendezvous.
T he rendezvous was suggested by H oare in a paper which is entitled
Com m unicating sequential processes to contrast with D ijk stra's Co
operating sequential processes" on which C hapters 3 and 4 are based.
Instead of presenting H o ares original work we choosc (o discuss the version
that is used in the A da program m ing language. A da was designed specify
cally for real-tim e systems program m ing which inherently uses concurrency.
T he A da facilities will probably become the dom inant style for concurrent
programming.
The exam ples will be writ(en as executable A da program s. However,
we will try to use only Pascal-like features when possible and we will note the
essential differences w here neccssary. This chapter is not a tutorial o n Ada
nor even on the full range o f concurrent program m ing facilities it) A da. It is
intended as an introduction to ihe rendezvous concept as used in A da. Ada
program m ers can regard the previous chapters as a description o f the scien
tific clim ate under which the A da concurrent program m ing prim itives were
developed.

6 .2

THE "A C C E P T " S T A T E M E N T

The m onitor has no life of its own. It is simply a collection o f da(a and
procedures that sit waiting to be invoked. In o ur model, the m onitor is an
igloo which is accessible to all processes that need it but which is just a
building that docs nothing on its own. Let us now imagine a story that will
give us a feel for the rendezvous.
Several processes, P arc riding around in the snow o n their dog sleds
(Fig. 6.1). Proccss Q owns a lodge A das Place which happens to be
strategically placed at an intersection of all Ihe tracks followed by the Pt.
Periodically, the P, reach th e lodge and wish to e n te r for a snack. If P t arrives
before Q has arrived to open the lodge then P x crawls into his sleeping bag to
wait for Q. W hen Q arrives they open the lodge, go inside and P t exchanges
the fresh m eat he has bagged for ready-to-eat meat sandwiches that Q
prepares.
U nfortunately, Q 's investm ent capital was too small and the lodge can
only hold two processes and one load of m eat and bread. Thus, if several

TH E "ACC EPT" STATEMENT

SECT-1>.2

95

Fig. A.I.

processes arrive at the sam e tim e or if several processes arrive when a


transaction is in progress, th en only o ne process P , can be in the lodge with
Q. The o thers must wait until P, leaves the lodge to resum e his hunt and Q
leaves the lodge to ride his sled lo the B akery to replenish his supply of
bread. W hen Q returns he can com plete a similar transaction with the other
processes.
Suppose now that a sudden blizzard has delayed the arrival of the P,.
T hen Q m ust wait. Since it seem s pointless to waste energy by heating the
lodge when there arc no custom ers, the lodge stays loeked and Q keeps
warm in a sleeping bag outside.
T he essential features to be abstracted from this story are:
(i) the symmetrical waiting o f the rendezvous whoever arrives first is
required to wait;
(ii) the com pletion o f a single transaction during the rendezvous;
(iii) the m utual exclusion o f the transaction conducted in Ihe confinem ents
o f the lodge; and
(iv) the two-way cxchangc o f inform ation (hat is the m ethod o f communica
tion betw een the processes in the rendezvous. L et us now examine the
A da program for (his story (Fig. 6.2).
The accept statem ent has the syntax o f a local procedure (without local
d ata declarations) which can appear em bedded within executable state
ments. T he call to the accept statem ent is syntactically identical to a proce
dure call. This is done intentionally so th at an operation can be implem ented

96

l i l t A D A RENDEZVOUS

CHAP. 6

us a sequential procedure o r a concurrent program w ithout informing the


user. However, unlike a m onitor procedure, the accept statem ent belongs to
proccss Q. Q must accept som ething in o rd e r lo continue execution. As
described in the story, if some P, executes a call before Q executes the accept
then P, is blockcd pending the rendezvous. Conversely, if Q executes the
accept and there are n o w aiting processes P, then Q is blocked pending the
rendezvous. Once Q and som e P,have executed the p air accept lodge and
lodge then we say that the ien d e 2vous has occurred.
procedure A dalodge Is
nttmberofprocesses: constant : . . . ;
(ask type process;
task Q is
entry lodge (meat, in food', sandwiches: ou( foody,
end Q;
task body process Is
walrus, victuals: food',
begin
loop
walrus : = huntwalrus;
lodge(walrus, victuals);
eat(victuals);
end loop;
end process-,
(ask body Q U
bread: fo o d ,
begin
loop
bread
visitbakery,
accept lodge(meat: in fo o d ; sandwiches: out fo o d ) do
cook(meat)-,
sandwiches : meat-t-bread;
end lodge;
end loop;
end Q;
P\ a rr a y (l . . num berofprocesses) of process;
begin
null;
end Adalodge;
6. 2 .

Rem ark To run this program , you will have lo supply the value of
numberofprocesses; a representation for fo o d ; subprogram s for huntwalrus,

SECT. 6.2

THE -ACCEPT" STATEMfcHr

97

eat, visitbakery, cook, and finally, the loop should be term inating and some
trace should be printed. (E nd o f rem ark.)
The rendezvous is considered to be in force during the execution o f the
statem ents betw een the do of the accept statem ent and the corresponding
end In particular, the calling process is blocked for the duration of the
rendezvous to prevent it from changing the values of the param eters until the
exchange of inform ation is com plete. T hus the body o f the accept acts like a
critical section. O nce the accept statem ent has term inated, the rendezvous
has been com pleted and a fresh accept statem ent must be issuedduring the
next cycle o f the loopto effect a n o th er rendezvous (with the same process
or with another). O f the two p aram eters, one is used to pass a value from the
calling process and the o ther to return a value to the calling process. This is
the two-way exchange o f inform ation betw een the processes.
T hat the rendezvous is suitable for distributed systems can be seen by
the following sketch o f how it might be im plem ented. P, executes lodge by
sending a signal to Q that il requests a rendezvous. P, then suspends itself
pending a reply from Q. The processor running Q registers the signal from P,
by an in te rru p te r by polling. Q eventually executes the accept statem ent and
notes that P, has registered a signal. Q replies to P, that rendezvous has
occurred and rem ains blocked until P, acknow ledges the reply with a mes
sage containing Ihe param eters o f the call. Q receives the param eters,
executes the statem ents following the do and then returns the result para
meters. U pon receiving the results, P, can unblock and continue com puta
tion. The program can even be im plem ented in a distributed m anner because
once the num ber and type of the param eters are agreed upon, the processes
can be independently designed and program m ed.
Let us now see how the binary sem aphore can be sim ulated by a
rendezvous (Fig. 6.3). H ere it is im portant to note that while the mutual
exclusion problem for two processes was solved by invoking passive
sem aphore procedures, with the rendezvous wc need lo create a new
sem aphore process to m ediate between P , and P ,. On Ihe o th er hand. P, and
Pj no longer need to acccss the same variable o r queue.
procedure mutualcxclusion is
task sem aphore is
entry wait;
entry signal;
end semaphore;
task body semaphore is
begin
loop
accept wait;
accept signal;
end loop;
end semaphore;

90

1HC A D A RENDEZVOUS

CHAP. 6

(ask P ,;
task body P, is
begin
loop
rem 1;
wait;
critl;
signal;
cod loop;
end P ,;
task P2;
task body P2 b
begin
loop
re m l;
wait;
c r itl;
signal;
end loop;
end P 2;
begin
null;
end m utualexclusion;

Fig. 4.3.

W hen a process P, executes the call to wait, it must block until the
sem aphore process executes its accept statem ent and the rendezvous is
achieved. T h ere are no param eters to be passed and no statem ents to be
executed within the critical section of th e accept statem ent. Once P , has
term inated the rendezvous, it is free lo e n te r its critical scction.
P 2 how ever will block when it (ries lo call wait because the sem aphore
proccss is w ailing for a rendezvous with a signal call. T hus until som e proccss
(i.e. P t ) executes a call \o signal, the sem aphore proccss is blocked and hencc
so is P 2. W hen P , com pletes its critical section, il accomplishes a rendezvous
with the sem aphore process at accept signal. T hen the sem aphore process
can com m encc its next cycle and accom plish a rendezvous with P 2.
Since ih e q u e u e s for th e accept state m e n ts a re req u ired to be
im plem ented as F IF O queues, this im plem ents a FIFO sem aphore: even if
P, overtakes P 2 after com pleting the critical section, ii will be placed after P2
on the queue of the sam e accept wait statem ent. N ote th at ihe q ueues are
FIFO in term s o f time of arrival at th e processor executing th e accept
statem ent. T hus, in a physically distributed system, closer processes may be
able to overtake m ore rem ote ones. Lockout is not a problem , however,

SECT. 6.2

THE SELECT STATEMENT

99

because once a proccss does e n te r Ihe q ueue, it need only wait for the finite
number of processes ahead of it to com plete.
We have shown how lo im plem ent a single sem aphore. If Ihe system is
to have several sem aphores wc will need multiple copies o f Ihc sem aphore
process so lhal calls to wait and signal can be param eterized to indicate which
semaphore process lo call. In Ada a (ask type can be defined and multiple
instances created by ordinary variable declarations. T hus an array of
sem aphore lasks can be declared and accessed by a simple array index.
Ada la n g u a g e n o tes

1.
2.
3.
4.

A da uses a m ain procedure w here Pascal uses program .


The token var is not used before variable declarations.
loop . . end loop is o ur repeat . . . forever.
Processes arc called tasks. A task must have a specification p art which
declares Ihc entrys: the name of Ihe rendezvous, if any. The body is
defined separately and contains ihe d ata and code local to the task.
5. A n in p aram eter is read-only. For simple param eters (his can be
im plem ented by call>by>value: (he actual param eter is evaluated and a
copy o f the value is passed (o (he procedure, o r in this case the body of
(he accept statem ent. An out param eter is write-only. It can be used to
copy a value from tlte procedure 10 a variable in (he calling program.
6. To declare several identical lasks, we declare a task type. T hen multiple
instances may be declared in an a rra y , as we have done.
7. The declaration o f a task autom atically initiates it. T hus the main
program body is null. No cobegin. . . coend is necessary, since the token
task calls for concurrent execution.

6 .3

TH E "S E L E C T " S T A T E M E N T

Turning to the bounded buffer problem , we find that the accept statem enl
is insufficient. Wc might uttem pi a solution with (he program fragm ents of
Fig. 6.4, using a buffer proccss betw een the producer and (he consumer.
Producer:
loop
append(v)\
end loop;
Consum er:
loop
take(v)\
end loop;

100

n i b AO A RENDEZVOUS

CHAP. 6

Buffer:
loop
acccpt appcnd(v: in integer);
accept take(v: out integer);
end loop;
r

F it. 6.4.

The only execution sequence possible is append, take, append, take. This is
Ihe vame as no buffer at all and wc could just as well make the rendezvous
directly between the producer and the consum er.
Producer-.
loop append(v); end loop;
Consum er:
loop
accept appertdiy: in integer);
end loop;
If you exam ine the bounded buffer solutions by sem aphores and
m onitors you find that what is needed is some way of conditionally achieving
a rendezvous. If the buffer is full, the rendezvous must only be with the
consum er; if em pty, only with the producer. If the buffer is neither full nor
em pty then Ihe rendezvous can be wilh w hichever of the processes is cur
rently waiting for the rendezvous. If both are waiting then we do not really
carc with whom the rendezvous is m ade as long as the buffer proccss is not
unfair. W ilh this background it should be possible to follow the A da solution
to the bounded buffer (Fig. 6.5). The program shows just the buffer task; the
producer and consum er are straightforw ard loops,
task b oundedbuffer is
entry append(v: In integer)-,
entry take(v: out integer);
end boundedbuffer;
task body boundedbuffer is
size: constant
b: arra y (0 . . size) o f integer;
inptr, outptr: integer;
n: integer;
begin
n :** 0; inptr : = 0; outptr :* 0;
loop
select
when n < * size >
accept append(v: in integer) do
b(inptr) : v;
end append;
n : + | ;
inptr :=* (inptr + 1) mod

s c c r.t)

THE SELECT' STATEMENT

101

or
when n > 0 >
accept take(v: out integer) do
v : * b(ouipir);
end ta ke;
n := /* 1;
outptr :* (ouip tr+ 1) mod size,
end select;
end loop;
end boundedbuffer,
^^
Before wc discuss the new features o f the select com m and, note th at the
critical section of the accept com m and do es not encom pass the entire buffer
processing but only (he physical exchange o f da(a. The updadng o f Ihe
internal pointers need not block (he producer nor the consum er who have no
access to these local variables.
T he select statem ent allows one to select betw een several alternatives
separated by or. The alternatives are prefixed by w hen-dauses called guards.
The guards are boolean expressions which establish what conditions m ust be
(rue for an alterna(ive to be a candidate for execution.
T he execution o f a select statem ent begins b y evaluating aU the guards.
T hen one of the open alternatives altern ativ es wi(h true g uards is
selected for execution. In the bounded buffer if one o f (he guards is no( (rue
then the o th er must be (n < = 0 implies n < = size and conversely, n > size
implies n > 0) so there is always an open alternative. If (he buffer is em pty,
only the first alternative can be selected. This is th e alternative that receives
data from the producer. Similarly if th e buffer is full, only the second
alternative is open to allow (he consum er to rem ove d ata from th e buffer. In
either ease, of course, the buffer proccss will block waiting for the relevant
rendezvous. N othing is lost by not rechecking a closed alternative since the
only way to em pty a full buffer is by consum ing.
T he difference betw een th e select statem ent and an If statem ent is seen
in the case that both guards are open. T hen if b o th Ihe consum er and the
producer are wailing for a rendezvous, we d o n 'l care which rendezvous is
accomplished. An if statem ent must specify which statem ent is to be
executed in this case.
B ut the select statem en t is even sm arter than tha(. Suppose (ha( (he
buffer is neither em pty nor full, but th at only the consum er is w aiting for a
rendezvous. If a choice is made betw een both o pen alternatives then we
could blunder into blocking on an accept append statem ent for which no
producer process is wailing. Thus if both alternatives are open but only one
accept statem ent has a process blocked o n it waiting for a rendezvous, the
select will choose (o execu(e the alternative th a t leads to an im mediate
rendezvous.
T here is an o th er possibility, nam ely th a t both alternatives are open but

102

THE A D A RENDEZVOUS

CHAP 6

(hat n either process is ready. R ath er than endlessly checking the guards
(whose truth will not change) o r arbitrarily blocking on one o f the accept
statem ents, the select statem ent will block sim ultaneously o n both accept
statem ents and cxecutc the first rendezvous to be accom plished.
This is the essence of the guarded com m ands" style o f programming:
avoid over-specification (as in an if statem ent) by allowing the com puter as
much freedom of choice as possible consistent wilh the correctness require
m ents of the program .
We now give a m ore formal description o f the general select statem ent.
select
when condition I = > accept entry 1 do statements end;
other statements
or
when condition! > accept en try! do statements end;
other statements
else statements
end select;
Remark 1 The else clause is optional (see below).
Remark 2 A guard may be identically true in which case the when
true > can be om itted.
Sem antics o f the select statem ent:
1. Evaluate all the guards to determ ine which alternatives are open.
2. If there arc o pen alternatives, determ ine which accept statem ents in
open alternatives have processes currently waiting for rendezvous.
3. If there are such processes, execute one of these alternatives. If there
are several open alternatives with processes waiting for rendezvous, the
selection am ong them is done arbitrarily.
4. If there are no o pen alternatives o r no waiting processes, execute the
else d a u sc if there is one.
5. If there are no wailing processes and no else clause, wait for (he first
process lo attem pt a rendezvous with an accept clause in one of the open
alternatives.
6. In the absencc o f an else clause, it is an e rro r for there to be no open
alternative.
We can dem onstrate the general select statem ent by assuming in our
story thal the ow ner o f "A d a's Place" has independent suppliers of both
bread and m eat and th at his only task is to m ake sandwiches. I hen if there
are no processes waiting at the lodge, he can profitably use the tim e to
prepare sandwiches (Fig. 6.6).
The guards are exhaustive (at all times at least one is true) and disjoint
(no two are ever simultaneously true) so exactly one iso p en . T he else clause

SECT 6 4

PROVINO PROPER ! IES OF THE RENDEZVOUS

IU3

is used to do some useful work if the second accept statem ent is open but
does not have a process waiting for the rendezvous. If the /*, are fast eaters,
they will have to wait but if they are often held up in blizzards, they can count
on fast service when they do return to the lodge.
procedure A dalodge is
fade type process;
task hunter;
task bakery;
task Q is
entry delivenneat(mt: In fo od);
entry deliverbread(br. in fo od);
entry lodge(snack: out fo o d );
end Q;
task body process is
victuals: food;
begin
loop
explore;
lodge(viciuab);
eat(victuals);
end loop;
end process;
task body hunter is
walrus: food;
begin
loop
hunt(walrus);
delivenneai(walrus);
end loop;
end hunter;
task body bakery is
roils: fo o d ;
begin
loop
bake(ro!ls);
deliverbread(rolls);
end loop;
end bakery;
task body Q is
bread, meat, sandwiches: fo o d ;

104

THE AD A RENDEZVOUS

CHAP t

procedure makesandwiches is
begin
cook(m eat);
sandwiches ;= bread+meai;
bread :m 0;
meal : 0;
end m ake sandwiches',
begin
bread :* 0;
m e a t: 0;
sandwiches
0;
loop
select
when bread 0 = >
accept deUverbread{br. in fo o d ) do
bread : = br
end deliverbread;
or
when meal = 0 = >
accept delivermeat(mi: in fo o d ) do
m e a t: = ml;
end delivermeat;
or
when ((bread < > 0) and (m eat < > 0)) or
(sandwiches < > 0) = >
accept lodge(snack: out fo o d ) do
if sandwiches=Q then
makesandwiches; end if;
snack : sandwiches;
sandwiches
0;
end lodge;
else
if (bread < > 0) and (m eal < > 0)
and (sartdw iches-0)
then makesandwiches; end if;
end select;
end loop;
end Q;
P: a rra y (l . . num berofprocesses) of process;
begin
null;
end Adalodge;
Fig. 6.6.

EXERCISES

6 .4

10S

P R O V IN G PROPERTIES OF TH E R E N D E Z V O U S

The developm ent of a satisfactory proof theory for synchronziation by


communication is an area o f current research. T h e concepts o f invariants and
eventuality propositions lhat have been so successful in proving synchro
nization by cooperation may need modification when applied to the rendez
vous.
A n im portant goal is to try to m ake Ihe proofs distributed: the proof of
one process ought not to require knowledge of the internal details of another
process. It ought to be possible lo construct com m unicating proofs: If you
promise to send me a message A/, (I do not care how or why you do so) then I
promise lo send you a message M 2.
Let us look at the bounded buffer task o f Fig. 6.5. First note that, since
the guards are exhaustive, there is no deadlock. Since the execution o f one
alternative m akes true the guard of the o th er alternative, there is no lockout
if we assume fair selection am ong open alternatives. A nother way o f show
ing eventuality is to note that if the producer produces indefinitely without
the consum er consum ing, ihe buffer must fill and the producers guard is
falsified, The proof of tiveness can thus be done by reasoning internal to the
buffer task.
The safety property is lhat ihe elem ents must be consum ed in the same
order (hat they arc produced. The internal behavior o f ihe buffer task is very
simple; whal must be shown is lhat a value that is produced must become the
newest elem ent o f ihe buffer and that the oldest clem ent of the buffer is lhat
which is consum ed.
Suppose that (he producer executes append(v). U pon achieving the
rendezvous, we can conclude that the value of the actual param eter has been
com m unicated to the formal param eter v of the accept statem ent. Upon
completion o f lltc rendezvous (com pletion o f the accept statem ent), this
value has been transferred to b[inptr] and has becom e the newest etem cni of
the buffer.
The general rule is the transfer of inform ation at the point of the
rendezvous. For an in param eter v, w hatever was true of v in Ihe calling
process before the rendezvous is true within the accept statem ent upon
achieving rendezvous. For an out p aram eter (such as the v in fake), whatever
is true o f v upon com pletion of the accept statem ent (such as that v is the
oldest buffer elem ent) is true of the actual param eter in the calling task.
6 .5

6.1

EXER CISES

Solve Conways problem in Ada.

6.2

Write programs for the readcr-w riter algorithms we have given.

6.3

Simulate a general semaphore in Ada.

6.4

Simulate a rendezvous by semaphores or monitors.

106

T ilt: A D A RENDEZVO US

C HAP.

6.5

In Fig. 6.7 are two possibilities for a monitor-like wait/signal facility. Specify
the behavior o f these solutions. Which is more like a monitor?

6.6

Discuss the priority scheme of the solutions to (he problem o f the readers
and the writers shown in Fig. 6.8 and com pare them with the solutions in
C hapter 5.

6.7

Prove the correctness o f the program s in Figs. 6.2 and 6.6.

6.8

(D ijkstra) W rite a program for partition by communication. Two disjoint sell


o f num bers 5 and T are given. I f f and / are Ihe num ber o f elem ents o f S a n d T,
respectively. Ihen upon completion o f the program, S should contain the s
smallest numbers in S U T and T should contain the t largest numbers in S U T.
A solution using two processes is outlined in Fig. 6.9. Prove its correctness.
Note The term ination o f the task upper is not specified. If you program this
solution in A da. cither learn about the term inate option in Ada o r introduce
explicit signals for termination.

task moiuiorfacilny 1 b
entry waif,
en try signal;
end m oniiorfacilityl;
task body monitorfaciluy I is
received: boolean-,
begin
received : = false;
loop
select
accept signal;
received (rue;
or
when received * >
accept m'ail;
received : false;
end select;
end loop;
end m onitorfaciluy 1;
(ask m onuorfacililyi is
entry wait;
entry signal;
end m on itor facility 2;
task body monitorfacility2 b
begin
loop
accept signal,
select
accept wait;
els* null;
end selecl;
end loop;
end monitorfucility2;
F ig . 6 . 7 .

tX tR C iy s
Usk readersandwrxters I it
entry startread;
entry endread;
entry sianw riie,
entry endw rite:
end re a d e n a n d w /ite r sl;
task body readersandwriiers 1, 1$
readers: integer,
begin
readers : 0;
loop
select
accept stanread,
readers := readers + 1,
or
accept e n d rea d;
readers := re a d e rs- 1;
or
when readers 0 = >
accept n a r iw ite :
accept e n d w rite;
end *elccl;
end loop;
end readersandw riiers 1;
talk readersandw riiers! Is
entry jfartrcoc/;
entry en d re a d ;
entry fror/tvnte;
entry endw rite;
end re a d ersa n d w rilerl;
task body rea d e rsa n d w n te ri Is
readers: integer;
begin
readers :=* 0;
loop
select
w hen ia/tHrt/eVtun = 0 " >
accept startread;
readers : rea d ers* I ;

or
accept e n d re a d ;
readers : = re a d e rs- 1,
or
when readers * 0 = >
accept narfHrrte;
accept rnc/tm /e;
loop
select
accept startread;
readers i r ea ifcr j+ l;
else goto I;
end select;

107

ID #

TH E A D A RENDEZVOUS

CHAP. 6

e n d lo o p ;
(( /# e n d s e le c l;
e n d lo o p ;

readersantlwriiers2\

e nd

F ig . 6.1.

A d a L a n g u a g e N o te s
1.

startwrite'count is

it p re d e fin e d fu n c tio n ( c a lle d a n a t t r ib u te in A d a ) th a t re tu rn s


Ih e n u m b e r o f ta s k s c u r r e n tly w a itin g to re n d e z v o u s w it h th e e n t r y startwrite.
2- <(/)) is a s ta te m e n t la b e l th a t is ih e ta rg e t o f d ie c o r r e s p o n d in g g oto .

tower

la s k

is

e n t r y sendmax(xx: In
e n d lower;
ta s k upper Is

integer)-,

e n t r y sendmin(yy: in
e n d upper ;

integer);

lower is
x, mx: integer;

ta s k b o d y
b e g in

mx

:=

ihe m axim um value in

j;

lo o p

sendmax{mx);
rem ove m x from S;
a c c e p t sendm in(xx: In integer) d o
x : xx;
e a d sendmin;
add x to S\
m x : the m axim um value in S;
e x it w h e n x s m x;
e n d lo o p ;
e n d lower;

upper
mn: integer;

la s k b o d y

is

b e g in
lo o p

sendm ax(yy\ i n integer) d o


add y y to T;
e n d sendmax;
m n : * the m inim um value in T;
sendm in(m n );
remove m n fro m T;
accept

e n d lo o p ;
e n d upper;
F ig . 6.9.

7.1

THE D IN IN G PHILOSOPHERS

INTRODUCTION

T he p ro b lem o f (he din in g p h ilo so p h ers (p o sed by D ijk s(ra ) is o f grcal


im portance in co n c u rre n t p ro g ram m in g research . T h e p ro b le m allows all of
the pitfalls o f c o n c u rre n t p ro g ram m in g to be d e m o n stra te d in a vividly
graphical situ atio n . Il is a challenge to p ro p o sers o f new prim itives for
concurrent program m in g . A s a te st o f y o u r u n d ersta n d in g o f concurrent
program m ing principles we p re sen t several solu tio n s using th e various
prim itives we have learn ed .
T h e p ro b lem is set in a m o n astery w hose five m o n k s a rc dedicated
philosophers. E ach p h ilo so p h e r w ould be hap p y to engage only in thinking
w ere it not occasionally necessary to c a t. T h u s the life o f a p h ilo so p h er is an
endless cycle: re p e a t think', eat forever.

P ig .

7. 1.

10 9

110

THE DINING PHILOSOPHERS

CHAP 7

The communal dining arrangement is shown in Fig. 7.1. Jn the center of


the tabic is a bowl of spaghetti that is endlessly replenished; there are five
plates and five forks. A philosopher wishing to eat enters the dining room,
takes a seat, eats and then returns to his cell to think. However, the spaghetti
is so hopelessly entangled that two forks are needed simultaneously in order
to eat. (It has been pointed out that this requirement is rather forced and that
it would be more natural to set ihc problem in the Orient with a bowl of rice
and chopsticks.)
The problem is to devise a ritual (protocol) that will allow the
philosophers to eat. Each philosopher may use only the two forks adjacent lo
his plate. The protocol must satisfy the usual requirements: mutual exclusion
(no two philosophers iry to use the same fork simultaneously) and freedom
from deadlock and lockout (absence of starvationliterally!) An additional
safety properly is that if a philosopher is eating then he actually has two
forks.
7.2

FIRST ATTEMPT

program diningphihsophers;
var
fork: array [0 . 4] of ( binary *) semaphore;
i: integer;
procedure philosopher(i: integer);
begin
repeat
think-,
wait( fork[i) );
wait( fork[(i+ I ) mod 5] );

eat;
sinal( furk[i] );
signal( fork[(i+ 1) mod 5] )
forever
end;
begin ( main program *)
for / : * 0 to 4 do fork[i) : * 1;

cobegin
ph ilo so p h er^);
philosopher^ 1);
philosopher(2)\
philosopher( 3);
philosopher{A)

coend
end.

SECT 7 3

SECOND A I I I MTI

III

The idea of the program in Fig. 7.2 is very simple. The binary
semaphores ensure mutual exclusion in accessing the forks. The safety
property is satisfied because eating is done onty after two fork-scnuiphores
have been successfully completed.
Unfortunately the solution deadlocks. Under pcrfcct sychronization if
the philosophers enter the protocol simultaneously and take the left forks
then the state of the program is that all forks are 0 and all the philosophers
are trying to complete wait(fork[i+1]). Since there is no proccss that can
signal, the program is deadlocked.

7.3 SECOND ATTEMPT

program
dinmgphitosophers;
monitor forkmonitor;
var
fo rk: array[0 . . 4] of integer,
oktoeat: array[0 . . 4] of condition ',
i: integer]
procedure takeforkij: integer);
begin
If fork[i] <> 2 then wait(pktoeat[i])\
fork[(i+ I) mod S] := fork[(i+ 1) mod 5 ]- 1;
fo r k \(i-} ) mod 5) := fo rk[(i- I) mod 5}J
end;
procedure releasefork(i: integer)-,
begin
fork[(i+ 1) mod 5] := fork[{i+1) mod 5 )+ l;
fork[(i~ 1) mod 5] := fo r k [ (i-1) mod 5 ]+ l;
Iffork[(i+ l) mod 5]=2 then signal(oktoeat[(t+1) mod 5]);
If fo r k [(i-1) mod 5)" 2 then signal(oktoeat[(i- 1) mod 5})
end;
begin ( m onitor *)

for i := 0 to 4 dofork[i] : 2
end;
procedure philosopher(i: integer);
begin
repeat
think;
takefork(i);
eat;
re/easefork(i)
forever
end;

1)2

THE DINING PHILOSOPHFRS

CHAP.?

begin (* m ain program *)


cobegin
philosopher^)-,
philosopher( 1);
phitosopher( 2 );
philosopher^)-,
phUosophcr(4)
cocnd
end.
Fig. 7.3.

T he previous solution tailed bccausc a philosopher is allowed to blindly


take a free fork. In ihe present solution (Mg. 7.3). the array fo r k is now
intended to represent tltc num ber of free forks available to a philosopher.
Only if both forks are available will the philosopher tak e th em (by complex
ing procedure takefork). The mutual exclusion am ong m onitor procedures
and the im m ediate resum ption of a signalled proccss ensure that the
intended m eaning holds sincc (i) no o th er process can access fo r k as long asa
process is in the m onitor, and thus (ii) the process lhat notes that two forks
are available can update the status o f fo rk [i~ 1] and fo r k [ i+ 1] before ils
neighbors can continue.
Freedom from deadlock can be shown as follows. L et eating = the
num ber o f philosophers eating. T hen when no process is in a monitor
procedure, it is easy to see lhat
4

/ - ( f o r k [ i] - \Q - 2 * eating)
I:I
is in v a r ia n t .

1 Initially eating 0 and 2 fo r k [ t] - 10.


2. fork[i] is decreased by 2 and eating is increm ented by 1 by every
process com pleting takefork.
3. fork{i] is increased by 2 and eating is decrem ented by 1 by every
proccss com pleting releasefork.
For deadlock to occur, we must have all processes waiting, and so
eating = 0. By / , fork[i] = 10. Thus ihc last process, say
to execute
takefork and wail must have found fo r k [ f) * 2 and w ould not have waited,
contrary to the assumption.
C onsider now th e scenario in Fig. 7.4.
Philosopher 2 is going to starve to death bccause philosophers 1 and 3
are conspiring lo cause a lockout. By o u r rules, if there is even o ne scenario
that leads to lockout, the solution must be rejected. Note that we do not
assume that a philosopher cats indefinitely as eating has th e status of a

|CT 7 4

A CORRECT SOLUTION

113

Critical scction. However, we cun assume lhat two philosophers think very
fc l and cat very slowly.
Action

fark[0]

Initially

i$kefork[ 1]

1
1

k tfo r k [ i)

mif/ork{2)
and wait
relctueforkH]
Uktfork[\)
rtUasefork[y\
u k e fo r k [ 3 )

1
2
t
1

fork{ I)

fork(2]

1
0

2
2
2
2

fork[3]
2

2
2

2
2

0
1

0
(

1
1

1
2

Fig. 7.4.
7.4 A CORRECT SOLUTION
program
var

/ork{4]

diningp/ufosop/iers;
fo rk: a rray {0 . . 4) of ( binary ) sem aphore;
room: sem aphore;
i: integer;
procedure philosopher#: integer);
begin
repeat
think;
wait{room);
wait( fork[i] );
wait( fork{(i+ \ ) mod 5 ] ) ;
eat;
signal( fork[i) );
signal( fork[(i+ 1) mod 5) );
sigrtal(room)
forever
end;
begin ( main program )
room := 4;
for i := 0 to 4 do fo rk[t\ : 1;
cobegin
p h ilo so p h e r^ );
philosopher^ I );
philosupher(2);
philosopher^ );
philosopher(A)
coend
end.

IH

THE DINING Ptlll.OSOI'H ERS

CHAf!

The solution in Fig. 7.5 is similar to the first attem pted solution cxccfl
for the additional enclosing sem aphore room . The safety properties hold*
before. D eadlock is not a problem since room ensures that at most f
philosophers are attem pting to access forks. By a simple application of the
pigeon-hole principle any attem pt to distribute the five forks in the circl^
am ong the 4 philosophers must result in at least one philosopher having twf
forks. The sem aphore invariant for the room is: room -I-(num ber o f process#
between w ait(room ) and signal(room ) )= 4 .
!
Iuit us now prove a series of lem mas that imply that this solution il
starvation-free.
"
l-cmma 7.1 If P, executes wait(fork[i}), eventually it will com plete the
P roof
|
If P, docs not com plete the wait it is only because fo rk[i]m0 which implies
that P_, is eating (since this is /V i's right-hand fork which was taken just
before ear). Eventually P,., finishes eating and cxccuies jjg/iu/(/brA;[/)) allow*
ing Pi to procecd.

( A dvanced) Rem ark Wc must assume some definition o f semaphores


(such as Morris*) stronger than the weak definition lo avoid elementary j
sem aphore lockout even am ong tw o processes. W hat we are interested in is ;
showing that lockout cannot be caused by conspiring processes. The previ*.
ous attem pt suffered from lockout even though the m onitor uses the strong
FIFO assum ption o n its queues.
I^m m a 7.2 If P, is waiting indefinitely on fo r k [i+ \] then P , is waiting
indefinitely on fo rk [i+ 2).
P ro o f

Only P, and P4t, "co m p ete for the sem aphore fork[i+ 1]. If P,4t is termi
nated in think th en fork[i+ 1] cannot block P,. Similarly. P, and PlM cannot
be sim ultaneously blocked on the same sem aphore fork[i+ I] (think of the
sem aphore invariant). Thus if P, is blocked on fo r k [ i+ 1] and P,,., is assumed
never to signal th at sem aphore, the only possibility left is for P,, to be
blocked indefinitely on the o th er sem aphore: fork[i+ 2].
Lemma 7.3 If Pt executes w ait{fo rk[i+ \))t eventually it will com plete the
wait (and eat).
P roof
By four successivc applications of Lem m a 7.2 wc have that if P, waits
indefinitely o n fo r k [ i+ 1] th en P ,+y w aits indefinitely on fo r k [ i+ j+ 1],
/ = ! ..........4 but this contradicts the sem aphore invariant for room.

7.5

.0

CONDITIONAL C R ITIC A L REGIONS

IIS

C O N D IT IO N A L C R IT IC A L REG IO NS

solution to the dining philosophers problem using sem aphores is difficult


write because o f the lim ited sem antic content o f the sem aphore opera
tions. A process can only test if an integer variable is zero and if so the
proccss is suspended. T hus we have no way of m aking a com pound test on
the value of two forks .
i
A synchronization primitive that does not suffer from this lim itation is
(he conditional critical region. A critical region is a prim itive for mutual
exclusion region r b e g in /),
end executes Ihe sequence of statem ents
i (, . . . , smas a critical scction. If several processes try to en ter the critical
region r sim ultaneously, th en only one successfully en ters and the others
must wait on a queue. W hen a process leaves a critical region, another
process from the queue is allowed to en ter. Similarly, if a process attem pts to
enter a region while an o th er process is within ih e region, th e new proccss
must join the queue.
Several regions can be declared lo allow distinct critical sections to be
entered sim ultaneously, just as several sem aphores or m onitors may be
declared.
The solution to the m utual exclusion problem is im m ediate (Fig. 7.6).

program mutualexctusion\
procedure ;>t ;
begin
repeat
rem 1;
region r begin crit 1 end
forever
end;
procedure p 3\
begin
repeat
rem 2;
region r begin crii2 end
forever
end;
begin ( m ain program *)
cobegin
P tlP t
coend
end.
Fig. 7..

116

TH E D IN IN G PillLOSOPHLRS

CHAP. 7

To solve more difficult problem s, the conditional critical region is used.


Competition for entry lo the critical region is allowed only if an entry
condition is satisfied. These are similar to the A da guards.
The syntax is: await b region r begin i , ;
end. T h e sem antics arc: 2>
is first evaluated. If b is true then the proccss may en te r the com petition to
en ter the critical region (and of course, succeed in entering if the region is
free). If b is false, the process must en ter tl>c queue of waiting processes.
W henever a process exits a critical region, all the processes waiting on
its queue arc released. T hose processes having entry conditions must re*
evaluate them . Processes with true conditions (including processes with no
conditions) then com pete to en te r the critical region. The im plem entation
should ensure that this com petition is fair", though FIFO is not specified as
it is in the monitor.
We let each process evaluate its own conditionthus allowing expres
sions o f arbitrary complexity, including those using local variables and
procedures. The price wc pay for this flexibility is the overhead of evaluating
such expressions repeatedly as the proccss com potes for entry into the
critical section.
If we com pare conditional critical regions with m onitors, we see that the
m onitor has ihc flexibility o f evaluating arbitrary expressions, but since the
condition is nam ed and explicitly signalled there is no busy wait overhead
incurred by repeated evaluation.
Sem aphores can be easily simulated:
Hw'j(.rw?): await sem > 0 region r begin sem : *= sctn~ 1 end.
signoi(sem): region r begin sent
se m + 1 end.
In Fig. 7.7 is a solution to the problem o f the dining philosophers using
conditional critical regions. T he solution is similar to th e m onitor solution
(Fig. 7.3). The conditional critical region primitive is here exactly what is
needed to accomplish the com pound test, som ething we could not d o with
sem aphores.
progra in diningph Hosophcrs;
var
fo rks: a rra y [0 . . 4] of integer-,
i: integer ,
procedure phitosophcr(i\ integer);
b e g in

repeat
think;
await fo r k s[i]-2
region r begin
forks[(i+ 1) mod 5] := forks[(i+ 1) mod 5 ) - I ;
fo rks[(i- 1) mod 5) : * fo r k s [ ( i- 1) mod 5 ] - 1
end;

EXERCISES

117

ear,

region r begin
fo r k s [ (i+ \) mod 5] := fo r k s[(i+ l) mod 5 ] + 1;
fo rks[(i~ I ) mod 5 ) : - fo rks[(i~ 1) mod 5]+ 1
end
forever
end;
begin ( main program *)
for / := 0 to 4 do f o r k s { i ] 2;
cobegin
philosopher^ 0);
philosopher(\y,
philosopher^ 2);
philosopher(3)\
philosopher(4)
coend

<
*
j
i
1

Conditional critical regions d o not have the theoretical appeal of the


elem entary sem aphores. Practitioners have overwhelm ingly preferred to
f implement the m onitor. T he effort involved is fully repaid by the flexibility
[ of the concept and by the benefits obtained by the structuring of the data and
procedures within a m onitor. The A da program m ing language, though it
uses a different prim itive, also cncourages encapsulation o f d ata and proce
dures in packages and (asks.

I 7.6 EXERCISES
I
' 7.1 Prove in greater detail ihe safety properties of the various algorithms.
7.2 Write one (or several) of the solutions in the chapter using the Ada rendez
vous.
7.3 Program 'he following algorithm (in any formulism): a philosopher wishing lo
cat picks up his lefi fork; if his right fork is available, lie picks it up and
commences eaiing else he releases his left fork and repeals this cycle. Discuss
the correctness of this algorithm.
i 7.4
!
|

All ihe solutions in this chapter are symmetrical, that is, all the philosophers
execute the same codc parameterized by the process number and furthermore
no process explicitly uses its process number in Ihe code. Try to find asymmet
rical solutions: program them and discuss correctness. Kor example: change
the first attem pted solution so thai one of Ihe processes executes
tvait(fork[i-i 1]) and then watt(fork[f\) instead of conversely.

7.5 Discuss ihe solution sketched in Fig. 7.8. We have deviated from Ada by
allowing a selecl statement wilh no accept clause. The cffecl is that of a
non-dctcrministic choice between the two possibilities.

118

THE DINING ritll.O SO PH ERS

task body fork is


begin
loop
select
( become Cs left fork )
Ufifork(i),
accept rcleauteftfork(i);
or
( become 1 + l s right fork *)
righsfork(i + 1);
accept releaserightfork(i+ 1);
ta d select;
end loop;
end;
task body philosopher is
begin
k>op
think,
select
accept Uftfork{i)\
accept righlfork(i)\
or
accept righifork(i),
accept ieftfork(i)\
end select;
ear,
rel<as<Uftfork(t\,
reteaserightfork (i),
end loop;

APPENDIX: IMPLEMENTATION KIT

A.1

INTRODUCTION

Soon, perhaps, every stu d en t of com puter science will have his own
minicomputer and sufficient tim e to team its hardw are thoroughly so th at he
may exercise concepts o f concurrent program m ing by building a real-tim e or
operating system from scratch. Until then, the accepted solution to class
exercise o f concurrent program m ing is to sim ulate concurrent execution.
T here arc several serious im plem entations which are noted in the
references. This appendix contains the listing and docum entation o f a very
simple system which can exercise concurrent execution with synchronization
by sem aphores. T his system can thus be used by any instructor who docs not
have access to one of the m ore serious systems. The system is not efficient
and is not intended to be used for extensive concurrent program m ing but it
has been successfully used to dem onstrate (the hard way) to students the
difficulties o f concurrent program m ing. Note th at even though the system is
written in Pascal, it uses only a subset o f the language th at could easily be
translated into any block structured language. Similarly, th e machine
dependencies (such as record packing to save space) are clearly noted and
easily changcd. This appendix, how ever, presum es a knowledge of Pascal.
The program in the listing (Section A .8) is a simplification and modifi
cation o f the Pascal-S interpreter originally w ritten by N. W irth. Pascal-S
com piles a subset o f Pascal into pseudo-code (P-code) for a hypothetical
m achine and then proceeds to in terp ret (sim ulate the execution of) this
code. The general structure of Pascal-S is shown in Fig. A. I .

program pascals;
v ar code: a rray [1 . . codem ax] of instructions',
procedure block;
119

120

IMPLEMENTATION K IT

APPENDIX

begin
Compile the Pascal-S program and store the com pded instructions in
the array code.
end;
procedure interpret;
var stack: array [1 . . stackm axJ of integer;
begin
Sim ulate the instructions in code.
The array stack serves as the m em ory o f the simulated computer.
end;
begin (* m ain program )
initialize;
b lo ck;
interpret;
end.
Fig. A.i.

The object language P codc is for a stack m achine. By this is m eant lhat
there are no registers or accum ulators as on most com puters. Instead, all
operands arc contained on a stack. A com m and such as A dd needs no
further specification since it autom atically refers to the operands on Ihc
stack: A dd the to p two elem ents and replace them with the result as the top
elem ent in the stack. This architecture has actually been used on real
com puters (such as Ihc Burroughs 6 700) and even on pocket calculators (of
(he IIP series).
In a slack machine A := B + C is com piled into the following sequence
of instructions:
1.
2.
3.
4.
5.

A .2

Load the address of A onto the stack.


Load Ihe value of B o n to the stack.
Load the value o f C o n to the stack.
A dd: rem ove the top two elem ents from the stack. Add them together
and store ihc result as the lop elem ent on the slack.
Store Ihc lo p elem ent in the address that appears just below il on Ihc
stack. Rem ove these tw o elem ents.

THE C O M PILE R

The subset of Pascal compiled is:


1.

Simple d ata types: integer, boolean, char.

2.

Structures: array s (including multidim ensional arrays)

3.

Strings: Only in Ihc form: write{# this is a title # ) .

4.

O perators: integer ( + ,

, div, m od); boolean (not, and, or).

i
?

SECT- A.J

5.

THE P-COOE

R elations:

< > , >, <, >=, >*.

6.

D eclarations: const, type, var, procedure, function.

7.

Statem ents:
assignm ent;
if b then s\
i f b then j , e ls e
while b do 5;
re p e a t

121

5 2>

; J* u n t il

b\

for / := e t to e 2 do j;
8.

Block structure: procedures and functions may be nested under Ihe


usual block structuring rules o f Pascal. T hey may have both variable
and value param eters.

9.

C oncurrency: in Ihe main program , a single com pound statem ent of


the form cobegin j , ; . . . ; sa coend is allowed to indicate concurrent
execution o f ........... .. s which must be globitl procedure calls.

10.

wait(s) and sig n a ls) are predefined sem aphore o perations looking for
integer variables. The initial value o f the sem aphore should be set by
an assignm ent statem ent in the m ain program . F o r pedagogical
reasons, a sem aphore type is provided. H owever, it is synonym ous with
iniegcr and provides no protection.

The com pilation is by top-down recursive descent. A sim ilar com piler is
extensively described in the book Structured System Programming by Welsh
and M cKcag (1 980) and thus wc d o not discuss it further except as needed to
understand the concurrent interpreter. The only point we feel obliged to
note is the use of a sim pler data structure for the identifiers. T hey are kept in
an array tab: the entry for an identifier contains a link fictd which contains
the index o f the previous identifier in th e same level o f block nesting.

A .3

TH E P-CO O E

The I'-codc instructions consist o f an instruction field and possibly iwo


operand fields* and y. x is used to point to th e static level as described below
and y is used to pass operands to the instructions. T he in terp reter uses the
following data passed to it by the co m p iler
btab ihe block table, discussed below.
atab the array tabte which has an entry for each array. The entries
contain the following fields:
low , high: the limits on the array index,
elsize: the size o f an array elem ent.
The following fields are used only by the com piler and will not
concern us further:

12 2

--------------------------------------------

IMPI.EM ENTAIION KIT

APPENDIX

size: the total size of the array,


<ltyp, inxtype: the types of the elem ents and the index,
etref: a po in ter to an entry in atab if the elem ents o f the array are
them selves arrays.
codeth e com piled P-code.
staba table containing all the strings in the program . A string is
identified by a starting index in stab and the num ber o f characters.
The m em ory of the interpreter is the array s which is treated as a
stack. All d ata arc stored as integers. C haracters may be stored and retrieved
using Pascal functions ord and cAr. For booleans we have w ritten functions
6ooleaiuo/nteger and /ntegcrto&oolean.
The pseudo-instructions are sum m arized in the following table: x and y
refer to the o p eran d fields o f the instruction and / is an index i n i for the top
of the stack. Instructions 0 - 7 , 1& -19,3 2 -3 3 will be fu rth er discussed later;
the others are straightforw ard.
0: Load A ddress
1: Load Value
2: Load Indirect
3: U pdate Display
4: Cobegin
5: Coend
6: Wait
7: Signal
8: E nd o f Line and End o f File
10: Jum p to address y
11: Jum p to address y if j[f] *s fak e
14: Precedes the code o f s in th e for-loop:
for i := e, to e 2 do s.
y th e address o f the instruction after th e loop
jf r -' !]* * ;
address of i
IS : Follows Ihe code of s in the for-loop. y address o f s
18: M arkstack
19: Procedure Call
21: Select an clem ent o f array atab{y] and push it o n to the stack.
4 /] * value of the index
22: Push y words from address 4 0 on to the sicck
23: Copy y w ords from address
to address
24: Push (he literal y o n to th e stack
27: R ead a value of type y into the variable whose address is jff]
28: W rite $(/] characters from jw 6[y]
29: W rite *[/]

SECT A J

THE P-CODE

123

31: Hall
32: R eturn from procedure
33: R eturn from function
34: j ( i ] is an address; replace il by its value
38: Store if i) at address i f f - 1]
35-36, 45-59: A rithm etic and boolean operations
62, 63: R eadln, W riteln
O thers: om itted in the simplification from W irths Pascal-S
In a block-structured language the address of a variable is d enoted by a pair
(Level, A ddress) w here Level is the dep th of nesting of blocks when the
variable was declared and A ddress is the offset of this variable within the
memory segm ent associated with this level. N ote th at the rules o f block
structuring require (hai blocks be nested. Thus the mem ory segm ents can be
stacked. To access a non-local variable, one simply follows the links which
define the nesting until the proper level is reached (Fig. A .2, w here s is a
local procedure of r which in turn is local to main program p). These links are
called static links.
I
i
i

t
i
i

Fit. A.2.

If, however, we are going to execute the P-code, we need some faster
way o f accessing a variable. T his is done by using a display which is an array
indexed by levels whose elem ents point to the m em ory segm ents represent
ing the current situation o f block nesting. T his is the sam e as saying that Ihe

12 4

IMPLEMENTATION KIT

APPENDIX

display holds the current static links. T he address o f a variable iscalculaied


by computing display[x]+y where (x, y ,)= (L ev el, A ddress).
Instructions 0 , 1 ,2, in the interpreter can now be understood asO: Load
an address; 1: Load a value; and 2: Indirect loading o f a value. 2 is used in the
case o f a var param eter w here what is passed to the procedure is the address
of the address o f a variable.
T here is a price that must be paid for the elegance of the display. Any
change in (he current block structure, i.e. a procedure o r function call must
update the display. Hopefully, thisoccurs infrequently relative to accesses to
the variables.

A .4

PR O CEDURE CALLS

During the normal execution o f a program by the in terp reter, the two main
pieces of dynamic inform ation that must be m aintained are p c (program
counter) which points lo the next instruction to be executed, and t which
points to Ihe current top of the slack. In addition, we m aintain b which points
to the bottom of the currcni stack segment and stacksizc which points to the
limit of the area allocated for the stack. Finally display keeps track of the
addressing by nesting level.
Each time a procedure o r function is called we need to allocate memory
for the local variables as well as for ccrtain additional inform ation, such as
the return address to jum p lo upon com pletion o f the procedure. It is
convenient to allocate this mem ory on Ihe same stack th at is used for the
operands and to d o the nccessary adjustm ents upon the procedure call and
return. The mem ory allocated upon procedure call is called an activation
record.
In Pascal-S an activation record has a fixed part of five words:
a/fO J^Function result;
flr[l] R eturn address;
flr[2)*S tatic link;
fl/,[3 ]D ynam ic link;
<v{4)=Tablc pointer.
W hen a function call is com pleted, the value of the function is left in
place o f the entire activation record. C onveniently, Ihen, the effect of a
function call is to push its result onto the stack just as if it were a normal
operand. The return address contains the address of th e instruction to be
executed upon procedure exit. T he table pointer contains the index into (he
identifier table tab for the procedure nam e. T he tab field adr contains the
index into the code (able o f the procedure code and re f contains the index
into the block table to be described shortly.

PROCEDURE CALLS

SECT A 4

125

If a procedure p has called a procedure q then the dynamic link of q


points to the start of the activation record o fp . It is used upon procedure exit
to reset the various stack pointers. T he static link points to the start of the
activation record of the procedure which textually encloses the called procedure. T his defines the block structure o f the language and can be either used
directly to acccss variables o r reflected in the display.
To understand the difference betw een a static and a dynamic link look
at Figs. A .2 and A .3 which show the activation records at two points during
Ihc cxccution of Ihc following program .
program p ;
procedure q\
begin . . . end;
procedure r,
procedure
begin . . . q . . . end;
begin . . . s . . . end;
begin (* m ain program *) . . . r . . . end.

H g . a .3

126

IMPLEMENTATION KIT

APPENDIX

In Fig. A .2, p has called r (which is local to p ) and th en r has called s


(which is local to r). The dynamic links show the sequence o f the calls. The
static links arc the sam e since s can access Ihe variables o f r (which called it)
and in tu rn r can access the variables of p (which called it). T he display
reflects the nesting levels 0, 1, 2.
In Fig. A .3, s has now callcd q , which is local to p and q cannot acccss the
variables o f r and s. This is indicated by the static p o in ter o f Ihe activation
record of q which is now pointing to the activation record o f p . N ote that
though the sequence of calls is longer, the display is now shorter.
As a check to see if you understand these concepts, draw the links for
some recursive procedure rec. T h ere will be a large num ber of different
dynamic linksone for each recursive call o f rec but th e static links will all
point to the sam e activation record: lhat of ihe procedure in which rec is
em bedded.
Wc now describe the mechanics o f a procedure call.
A procedure or function call is com piled into:
18: M ark stack;
Compile the param eters;
19: Call;
3: U pdate Display (if necessary).
T he activation record consists of:
(1) ihe five word fixed area;
(2 ) an area for the actual param eters (w hether values o r addresses), and
(3) an area for the local variables o f the procedure.
The array btab contains an entry for each procedure with fields: psize
which is the sum o f the lengths of areas (1 ) and (2 ) and vsize which is the sum
o f psize and (he length o f a rea (3). vsize is thus the total size o f th e activation
rccord for this procedure. (T here are also two fields la stm pointer to the Iasi
identifier in this procedure and lastpar - p ointer to the last param eter in ihis
procedure. T hese are used only during the com pilation and not during the
sim ulation). 6 /a 6 fl]
an entry for the environm ent block containing
predefined identifiers like integer. btab{2] is thus Ihe entry for the main
program .
T he instruction M arkstack is passed the index o f Ihe procedure nam e in
the identifier table tab. Sincc the actual param eter evaluation may involve
arbitrarily com plicated com putation, the main purpose o f Ihe M arkstack
instruction is to advance ihc slack pointer by five w ords so as to leave room
on the stack for the fixed area. T hen the evaluation o f the param eters may
freely use the stack above the fixed area.

PROCEDURE CALLS

SECT. A .4

127

In addition, M arkstack perform s the following services. Since the pro


cedure nam e is seen and com piled before the actual p aram eters, the proce
dure nam e (via a pointer to the indenlifier table) is conveniently passed at
this point to the interpreter. M arkstack stores this operand in ar{4] for
subsequent use by the Call. M arkstack also checks th at there is sufficient
room in the stack for the activation record (w /z) and tem porarily stores
vsize in the slot lo be used by the dynam ic link.
Now the actual param eters can be com puted. T he com piler has deter
mined that when this has been com pleted, (he stack pointer I will point to
psize words beyond the start of the activation record and in fact psize
(actually ( v / p ) s i z e - \ is stored to use as an offset) is passed as the operand to
Call. T he stack a t the beginning o f Call is shown in Fig. A .4.

Parameters
Index
+4
+ 3 fcfeJ>( J .v s iz e 1
+2
+1
+0

btab\ ) psize

/(before M arkstack)

Local variables
of
m ain program

4 ~FtabJTj~JSsT
3
2
I
b -*-

blab [2] .vsize

W ith a slightly m ore descriptive notation th an th e bare listing, the code


of Call is shown in Fig. A.S. Fig. A .6. shows the stack following the com ple
tion of the procedure call. P rocedure exit is relatively simple (Fig. A .7).

i^ T m r .- s a

128

IMPLEMENTATION KIT

a p p e n d ix

otdb : * fc;
b :* t - y;
inx : 4 ^ + 4 ] ;

/ := 4fc + 3]+6;
/eve/ ;* <a6{m.x]./v,
4 ^ + 2] := display[lcvel],
display[tevel+ \] : b;
4/> + 3] ;= o td b;
4 * + 1]
pc\
p c :* iab[inx}.adr,

( Save Ihe previous bottom o f slack for


the dynamic link )
( New bottom slack is com puted from
psize as passed in y )
(* Retrieve index o f procedure in /a 6 a s
left by M arkstack )
(* C om pute new to p of slack from vshe
lefi by M arkstack )
( G el nesting level in which procedure
is defined *)
( Static link is the bottom of the stack
segm ent of th e level o f definition *)
(* The procedure executes one level up,
so update the display *)
( Set the dynamic link *)
(* R eturn address *)
( Jum p to the procedure code )
H f.

.s .

stacksize

LocaJ
variables

Parameters

+4
+3

Index
Dynamic link
+2
Static link
+1
Return address
for function result

psize

vslze
F ir

a .*.

CONCURRENCY

SECT. A.S

I := b -

I;

pc
s[b + 1];
b : = s[b + 3];

129

( R estore th e old lop o f the stack. For


a function exit this is I := b \ )
( R estore return address )
( Restore bottom o f stack from the
dynamic link *)
Fig. A.7.

T here is one m ore problem that must be solved. If the procedure call is
(o a procedure on a lower static level than (hat o f the calling procedure, the
display will not be corrcct upon exit. In Fig. A .3 w hen the execution of q
term inates, only d is p la y 0) pointing to the activation record of the main
program will be correct, displayi 1] and display[2] m ust be m ade to point to
the activation records o f r and s, respectively. T his is d one by th e interpreter
instruction (3): U pdate display(x, y ) which updates display{y] down to
display[x\ by following the static links. In this case, the com piler must insert
U pdate d isp la yi), 2 ) which will cause 6currently pointing to the bottom of
the activation record of s to be stored in display{2] and then obtain from the
static link the index of the bottom of the activation record of r to store in
displayi 1].
This com pletes o u r discussion o f Pascal-S as applied to sequential
programs. Before reading fu rther you might want to think of the problems
that will be encountered in extending the system to concurrent execution.
A .5

CONCURRENCY

To execute several processes concurrently we need to m aintain: a stack for


each process which will be used for the local data of Ihe process (including
the d aia of any procedures called by the process) and a set o f register images
for each proccss. T o execute a particular process, its im ages are loaded into
the physical registers before execution.
In the case of Pascal-S registers are pc. the stack pointers b, t and
stacksiie and display. We m aintain a table pta b * with one entry for each
process containing this inform ation as well as two further pieces of informa
tion: active indicating w hether this process is active (as opposed to term i
nated) and a pointer suspend which points to a sem aphore if th e process is
suspended on a sem aphore. T he register images are loaded into (he
interpreter by the with ptab[curpr] statem ent which m akes all references to
the above variables take th eir values from the entry for the current pro
ccsscurpr.
t The constant pmax controls (he size of plab and hence the number of concur
rcnt processes allowed. For most efficient use of central memory, il is best to
lailor a version of the kit for each class cxercise. Conway's problem (Exercise
4 2) runs with pmax 3 but Parnas' problem (Exercise 4.15) needs pmax * 9.

130

IMPLEMENTATION KIT

APPENDIX

Similarly wc should have a sei of slacksone for the main process


(which contains all the global variables) and one for each concurrent pro
cess. If this is done, however, the interpreter would have to be passed an
index to the stack table on each memory access. A simpler solution is to
divide the single physical slack (the array j ) inlo several logical seg
mentsone for each process. Then as long as the displays are correct, all
accessing is done normally. See Fig. A .8.

F ig . A . t .

For simplicity, the slacks are pre-allocated. The use of dynamic alloca
tion does not involve any conceptual difficulties but for our purposes it
seems unnecessary. Various versions of this system can be tailored to suit
each assigned exercise.

program p\
procedure q;
begin . . . end;
procedure r,;
begin . . . q . . . end;
procedure r2;
procedure i;
begin . . . q . . . end;
begin . . . s . .. end;
begin (* p )
cobegin
r3 coend
end.

Hg. A. 10.

IMPLEMENTATION KIT

APPENDIX

type sym bol^(intcon, charcon, siring,


noisy, plus, minus, limes, idiv, imod, andsy, orsy,
eql, neq, gir, geq, Iss, leq,
Iparent, rparent, Ibrack, rbrack, comma, semicolon,
period,
colon, becomes, consisy, typesy, varsy, functionsy,
proceduresy, arraysy, programsy, ident,
beginsy, ifsy, repeatsy, whitesy, forsy,
endsy, elsesy, untilsy, ofsy, dosy, losy, thensy);
index** -x m a x . . +xmox\
alfa=packed array [1 . . alng] of char;
object= (konsiani, variable, type 1, prozedure, funktion);
typ es-(n o typ , ints, boots, chars, arrays);
e r-(erid , ertyp, erkey, erpun, erpar, ernf, erdup, erch, ersh, erln);
sym set-sH of symbols
typset*set of types;
item record
typ: types; ref: index;
end;
o rd e r -packed record
f: omax . . +omax;
x: Imax . . +lmax;
y: nmax . . +nm ax;
end;
var sy: symbol;
( last sym bol read by irtsymbol*)
id: alfa;
(identifier from irtsymbol)
inum: integer;
('integer from irtsymbol*)
m u m : real;
(*reat num ber from insymbol*)
sleng: integer;
(*string length*)
ch: char;
(*last character read from source program)
line: array [1 . . ling) of char;
cc: integer;
{*character counter*)
Ic: integer;
(*program location counter*)
It: integer;
(*length o f current line*)
errs: set of er;
errpos: integer;
progname: alfa;
skipflag: boolean;
constbegsys, typebegsys, blockbegsys, facbegsys, statbegsys:
sym set;
key: array [1 . . n * * ] o f alfa;
ksy: array [I . . nkw) of symbol;
sps: array [char] of symbol;
(special symbols*)

SECT. A.a

PROGRAM LISTING

t, a, b, sx, c,, ct : integer,


stantyps: typser,
display: array [0 . . tmax] of integer,
tab: array (0 . . tmax] of
packed record
name: alfa; link: index-,
obj: object; typ: types;
ref-, index; normal: boolean;
lev: 0 . . Imax; adr: integer;
end;
atab: array [ 1 . . amaxJ of
packed record
inxtyp, eltyp: types;
elref, low, high, elsize, sh e : index;
end;
array [1 . . bmax] of
packed record
/ojf, lastpar, psize, vsize: ini*lex

135

(* indices to tables*)

(*identifier table*)

(array-table*)

(block-table*)

end;

stab: packed array [0 . . smax] of charr;


code: array [0 . . cmax) of order;

(*string table*)

procedure errormsg;
var k: er;
msg: array [er] of alfa;
begin
msg[erid] := # identifier#; m s^ertyp]
fftype
tt;
ms&erkey] := ttkeyw ord t t ; msg[erpun) :* ttpunctuatio#;
msg[erpar] : # parameter tt; msg[ernf\ : ft not fo u n d #;
msg[erdup] := ttduplicatett; msg[erch] :* # character # ;
msg[ersh]
ttioo short tt; msg[erln} : ttioo long #;
mcssage(# compilation errors#);
writeln; writeln(# key wordsft);
for ft := erid to erln do if k in errs then
wruetn(ord(k), tt #>msg[k])
end (errormsg*);
procedure endskip;
begin (underline skipped part o f input*)
while errpos < cc do
begin w riie(tt-tt); errpos : errpos+1
end;
skipflag :** false
end (endskip*);

136

IMPLEMENTATION KM

APPENDIX

procedure nextch; (read next character; process line end*)


begin if cc-U then
begin If eofiinput) then
begin writeln;
writeln(tt program incompletett);
errormsg; goto 99
end;
if errpos < > 0 then
begin if skipflag then endskip;
writeln; errpos := 0
end;
write(lc:5, tt tt);
11 := 0; cc = 0;
while not eoln[input) do
begin / / : - / / + ! ; readich); write(ch); line\lt] := ch
end;
writeln; / / : = / / + ! ; read(line[U\)
end;
cc : cc+ !; ch : = lirte[cc];
end (*nextch);
procedure error(n: er);
begin if errpos - 0 then write{# *+#);
if cc > errpos then
begin write(tt tt: cc-errpos, # '# , ord(n):2);
errpos
cc+ 3 ; errs :=
end
end (*error );
procedure faial(n: integer);
var msg: array [1 . . 6] of alfa;
begin writeln; errormsg;
1] *
toidentifiertt;rnsg[ 2] :=
# procedures#;
msg[ 3] :m
tostringstt; rnsg[
4] :=
tt arrays # ;
m s 5} # levels
tt; msg[ 6j := ttcode
tt;
wriieln(# compiler table fo r tt,
tt is too sm all#);
goto 99 (* terminate compilation*)
end (fatal*);
(* ...............................................................................................insymbol-*)
procedure insymbol; (* reads next symbol*)
label 1,2,3;
var i, j, k , e: integer;

SECT. AS

PROGRAM LISTING

begin (*insym bob)


1: while c h ~ ff # do nexlch;
case ch of
tta tt, # b # , ttc ti, ttd tt, tte tt, U ftt, ttgU . U htt, UiU,
# ) # , Uk U, ttitt, H m # , ffnff, tto tt, ttp tt, U qtt, ttrtt,
ffs tt. Utft, H u h , # v tt, ttw tt, tt x tt, tty # , ttz#'.
begin (*identifier or wordsymbol*) k : 0; id :* ft
#\
repeal If k < alng (hen
begin k := A-M; id[k] := ch
end;
nexlch
until not (ch in [ft a f t . . ftztt, ttOft. . # 9 # ]);
i
I; / :* nkw \ ( binary search*)
repeal k := (i+y) div 2;
if id < = key[k\ then /
k -l;
if id > m k e ^ k \ then i := ic+ 1
until i > j\
If I - I > / then sy := Afy[A:] else sy : idem
end;
ttQtt, t f l f t , # 1 # , t f l f t , ttA tt, ftSft, t t t t t , t f l f t , t t l t t , tt9ff\
begin ('num ber*) k := 0; inum : = 0; sy : = intcon',
repeat inum :* inum* 10 + ord(ch) - ord(ttOft);
k :m k +1; nexlch
until not (ch in ( # 0 # . . # 9 0 ]) ;
if (k > krnax) or (mum > nmax) then
begin error(ertn)\ intun := 0; A :* 0
end;
end;
tt\tf, col; begin nexlch;
if ch - f t * t f then
begin sy : = becomes-, nextch
end else sy
colon
end;
tt< tt : begin nexlch;
If ch ft * ft then begin sy : = teq\ nexlch end else
if ch tt> # then begin sy := neq\ nextch end else
sy :* Iss
end;
tt> # : begin nextch,
if ch f t - f t then begin sy : = geq; nextch end else
sy := gtr
end;
: begin nextch;
If ch - ft .ft then

138

IMPLEMENTATION KIT

APPENDIX

begin sy : colon-, nextch


end else sy : period
end;
tftttftf-. begin k := 0;
2: nextch;
itc h - f t t f t f t f (hen
begin nextch; U ch < > U ttttU (hen goto 3
end;
If sx+ k ~ smax then fotal(3);
; ch; k := ft + 1;
if cc * 1 (hen
begin (*end o f line*) k : 0;
end
else goto 2;
3: if k ** 1 then
begin sy : charcon; inum : ord(stab[sx))
end else
if k = 0 (hen
begin error(ersh); sy
charcon; inum := 0
end else
begin sy : string; inum := sx; steng
k; sx := sx+ k
end
end;
# ( # : begin nextch;
if ch < > tf*ff (ben sy : Iparent else
begin ('com m ent*) nextch;
repeat
while ch < > tt* tt do nextch;
nextch
until ch = # ) # ;
nextch; goto I
end
end;
# +# . f t - f f ,
:
begin fy
sps[ch); nextch
end;
ttU t,
# . # , ft r # , ft'ft, # # , # & # , ff/ft :
begin error(erch); nextch; goto 1
end
end
end (*insymbol*)\
enter )

SECT A S

PROGRAM MSHNG

procedure enter (x0: alfa; x,: object',


x 2: types; x s: integer),
begin t : = ( + 1 ; Renter standard identifier*)
with tab[t) do
begin name : x0; link := / - l ; 067 :=
/>/> : x2; ref :m 0 ; normal :m true;
fcv :* 0; ad/- := x ,
end
end (vnter*);
procedure enterarray(tp: types', l,h : integer);
begin if / > h (hen error[ertyp);
if (abs(l)>xm ax) or (abs(h)>xmax) then
begin error(ertyp)\ / : = 0 ; /i : = 0 ;
end;
if a - amax then fatal(4) else
begin a
a + 1;
with alab[a] do
begin inxtyp : tp; low : /; high : h
end
end
end (*enierarray);
procedure enterblock;
begin if b - bmax then fatal( 2 ) else
begin b :* b + 1 ; btab[b]. last := 0 ; btub[b]. lastpar := 0
end
end (enterblock*);
procedure emitfjet: integer);
begin if Ic cmax then fatal( 6);
code[lc]. f ;= fct; Ic := lc + 1
end (*emit*);
procedure emit I (fct, b: integer) ;
begin if Ic-cm a x then fatal( 6 );
with code{lc) do
begin / : fct; y :* b end;
Ic := /c + 1
end (tf/n/il*);
procedure emit2(fct, a, b: integer);
begin If Ic cmax then fatal(6 );
with code[lc] do
begin /:* fct; x : a; y : b end;
l c : ~ lc+ l
end (*emit2*);

13V

140 IMPI KMENTATION KIT

APPENDIX

block *)

procedure block(fsys: symset; isfun: boolean; level: integer);


type conrec
record tp: types; i: integer end;
var dx: integer;
prt: integer;
prb: integer;
x: integer,

(data allocation index*)


(t-index o f this procedure*)
(*b-index o f this procedure* )

procedure skip(fsys: symset; n: er);


begin error\n); skipflag :* true;
while nol (sy in fsys) do iruymbol;
If skipflag Ihen endskip
end (skip*);
procedure test(s,, st: symset; n: er);
begin If not (sy in *,) then
skip(s, +s2, )
end (*//);
procedure testsemicolon;
begin
If sy = semicolon then insymbol ebe error(erpun);
test([ideni]+blockbegsys, fsys, erkey);
end (testsemicolon*);
procedure entered: alfa; k: object);
var /, /: integer;
begin If t tmax (hen fatal(l) else
begin tab{0]. name : id;
j
b(ab{display{tevel)}. last; I : j;
while tab{j]. name < > id d o / : tab[j]. link;
If; < > 0 (hen error(erdup) else
begin t := / + ! ;
wilh tab[t] do
begin name : id; link := I;
obj ;= k; typ
notyp; ref := 0; lev :* level; adr := 0
end;
btab[display[let>cf)]. last : = t
end
end
end (*enter*);

SECT. A 8

P R O G R A M L IS T IN G

function toc(id\ alfa): integer,


var /, j: integer; (locate id in table*)
begin i := level; w/>{0]. name : = id; (sentinel*)
repeat / := btab[display[i)]. last;
while tab[j].name < > id do / := tab[j]. link;
i := i - l ;
until (*<0) or (j<>0);
If j 0 then error(emf); loc
j
end (/oc*);
procedure entervariable;
begin if sy = idem then
begin enter(id, variable); insymbol
end
else error(erid)
end (entervariable*);
procedure constant(fsys: symset; var c: conrec);
var x, sign: integer;
begin c. tp :* notyp; c . i : 0;
fest(eonstbegsys, fsys, erkey);
if sy in constbegsys then
begin
If sy charcon then
begin c. tp :* chars; c. i := inum; insymbol
end
else
begin sign := 1;
If sy in [plus, minus] then
begin If sy = minus then sign := - 1 ;
insymbol
end;
if sy =* idem then
begin x := loc(id);
if x < > 0 then
if tab[x\ obj < > konstant then error(ertyp) else
begin c. tp :=
typ;
c. i :
adr
end;
insymbol
end
else
if sy intcon then

141

1-12

IM P L E M E N T A T IO N

KIT

A P P E N D IX

begin c. tp := ints ; C. i : sign*inum; insymbol end


else skip(fsys, erkey)
end;

test(fsys, (J, erkey),


end
end

procedure typ(fsys: symset; var tp: types', var rf, sz: integer)',
var j:: integer,,
eltp: types; elrf. integer;
els2, offset, t0,
integer;
procedure arraytypiyar arefarsz: integer);
var eltp: types;
tow, high: conrec;
elrf, elsz: integer;
begin constantdcohn, rbrack, ofsy\+fsys> low);
i f sy * colon then insymbol else error(erpun);
constantdrbrack, comma, ofsy)+fsys, high);
i f high, tp <> low. tp then
begin error(enyp); high, i :* low. i
end;

enterarray(hw. tp, low. /, high, t); oref := a;


i f ay = comma then
begin insymbol; eltp
arrays; array!yp(elrf,elsz)
end else
begin

sy = rbrack then insymbol else error(erpun);


sy = ofsy then insymbol else error(erkey);
typifsys, eltp, elrf, eh:)
If
if

end;

with atab{aref) do
begin arsz
(high-low+l)*elsz; size : arsz;
eltyp : eltp; elref : elrf; elsize := elsz
end;
end

(*arraytyp*);

begin (*typ) tp
notyp; r f :* 0; sz :* 0;
test{typebegsys, fsys, <);
I f j y In typebegsys then
begin
i f sy

then

SECT. A .8

P R O G R A M L IST IN G

begin x : loc(id)]
if x <> 0 then
with tab{x] do
If obj <> typel then crror(crtyp) else
begin tp : = typ; r f :* ref; sz ;= adr;
If tp notyp then error(ertyp)
end;
insymbol
end else
if sy * arraysy then
begin insymbol\
i t sy * Ibrack then insymbol else error(erpun);
tp : arrays', arraytyp(rf, )
end else
test(fsys, ( ], erkey);
end
end (*typ*);
procedure parameterlist; (formal parameter list*)
var tp: types;
rf, sz, x, t0: integer;
valpar: boolean;
begin insymbol; tp :- notyp; r f := 0, sz := 0;
test([ident, varsy], fsys+[rparent), erpar);
while sy in [idem, varsy] do
begin if sy <> varsy then valpar := true else
begin insymbol; valpar : false
end;
;= t; entervariable;
while sy m comma do
begin insymbol; entervariable;
end;
if sy m colon then
begin insymbol;
if sy <> idem then error{erid) else
begin x := loc(id); insymbol;
if x < > 0 then
with tab[xJ do
if obj <> type 1 then error(ertyp) else
begin tp ;= typ; r f :* ref;
if valpar then sz :m adr else sz : 1
end;

*
144

IM P L E M E N T A T IO N K IT

APPJ-N

end;
te st([sern ic o lo n , rp a re n t), [ c o m m a , id e n t] + fs y s , e r p u n )
end
else e r r o r(e rp u n );
w hile t0 < t do
begin t0 := f0+ I ;
w ith
do
begin ty p := tp ; r e f r f ;
n o r m a l : = valpar; a d r : = d x ; le v : level;
d x := d x + sz
end
end;
i f s y < > rp a re n t (hen
begin I f s y s e m ic o lo n (hen in s y m b o l ebe e r r o r(e rp u n );
te st([id e n t, va rsy], [rp a r e n t]+ fsy s, e r k e y );
end
end (w h ile * );
i f s y = r p a re n t then
begin in s y m b o l;
te st([s e m ic o lo n , co lo n ], f s y s , e r k e y );
end
else er r o r(e rp u n )
end (p a r a m e te r list* );
procedure co n sta n td ecla ra tio n ;
v a r c: co n rec;
begin in s y m b o l;
te st([id en t], b lo c k b e g s y s , erid );
w hile s y - i d e m do
begin e n te r (id , k o n s ta n t); in s y m b o l;
I f s y ^ e q l (hen in s y m b o l else e r r v r (e r p u n );
c o n s ta m ([ s e m ic o lo n , c o m m a , id e n t] + fs y s , c );
tab[t]. ty p
c. tp ; tab[t]. r e f : * 0;
ta b [t). a d r : = c . i;
te stse m ic o lo n
end
end ( c o n s ta n td e c la ra tio n );
procedure ty p ed ecla ru tio n ;
v a r tp : ty p es; r f, s z ,
integer;
begin in s y m b o l;
te st([id e n t), b lo c k b e g s y s , erid );
w hile s y = id e n t do

SEC T . A .S

P R O G R A M L IST IN G

begin e n te r e d , i y p e \ ) ; / , ; = / ; insym bol-,


i f s y - e q l then in s y m b o l else e r r o r(e rp u n );
ty p ([ s e m ic o lo n , c o m m a , id e n t] + fs y s , tp , r f, ) ;
w ilh ta b [ fK\ do
begin ty p : = tp , r e f : * rf; a d r := s z
end;
te stse m ic o lo n
end
end ( ty p e d e c la ra tio n * ) ;
procedure v a rta b ltd e c la r a tio n ;
var
r f, sz: in teg er,
tp: types-,
begin in s y m b o i,
w hile s y = itle n t do
begin t := /; en terva ria b le;
w hile s y - c o m m a do
begin in s y m b o i, en terva ria b le;
end;
i f s y = c o lo n then in s y m b o i else e r r o r(e rp u n );
f. : = t;
ty p ( [ s e m ic o lo n , c o m m a , id e n t\+ fs y s , tp , r f, s r);
w hile f < I j do
begin t9 : f0+ 1;
w ilh /a 6 [lu] do
begin ty p := tp ; r e f : * r f,
le v : = le v e l; a d r : d x ; n o r m a l : = tru e;
dx
d x + sz
end
end;
te stse m ic o lo n
end
end ( v a ria b le d e c la ra tio n );
procedure p r o c d e c la r a tio n ;
v a r is fu n : b o o le a n ;
begin is fu n :m s y fu n c tio n s y ; in s y m b o i;
i f sy < > id e n t Ihen
begin err o r(e rid ); id
tt
#
end;
i f is fu n then e n te r (id , fu n k iio n ) else e n te r (id , p r o ze d u re );
ta b [t\. n o r m a l
tru e;
in s y m b o i; b lo c k ([ s e m ic o lo n ] * f s y s , is fu n , le v e l + i );

146

IM PL E M E N T A T IO N K IT

APPEN D IX

i f s y ~ sem ico lo n (hen in s y m b o l else erro r(erp u n );


e m u ( 2 2 + o r d (is fu n ) ) ( < { )
end (*proceduredeclarauon*);
( .......................................................................................................- sta te m e n t--)
procedure sta tem en tijsys: sym se t);
var i: integer, x \ ite m ;
procedure e x p ressio n \fsys: sym ser, va r x : item ); fo rw ard ;
procedure selecior[fsys: sym set; var v: item );
var x: item ; a , /: integer;
begin
i f s y < > (brack then error(ertyp);
repeat in sym b o l;
expression (fa ys+ [ c o m m a , rbrack], x );
i f v. ty p < > arrays (hen erro r(ertyp ) else
begin a :=* v. ref;
i f atab[). in x ty p < > x . ty p (hen e rro r(e rtyp ) else
e m //l(2 1 , a );
v. ty p := atab{a\. ettyp; v. r e f : owbfa). elre f
end
u n til s y < > co m m a ;
i f s y = rb ra ck (hen in s y m b o l else erro r(erp u n );
te st(fsyst [ ], erk e y );
end ( * selector*);
procedure catt{fsys\ sym set; i: integer);
va r x : item ;
la stp , c p , k: integer;
begin
<'); ( * m a rk sta ck )
lastp := btab[tab{i). ref\. lastpar; cp : = /;
i f s y ** Jparent (ben
begin ( a ctu a l pa ra m e ter list*)
repeat in sy m b o l;
i f c p > lastp then error(erpar) else
begin c p : * c p + 1;
i f tab{cp\. n o r m a l (hen
begin {*value param eter*)
e x p re ssio n (fsy s+ [c o m m a , c o lo n , rp a ren t], x );
i f x . typ = ta b [cp ], ty p (hen
begin
Jf jr. r e f < > lob[cp). r e f (hen e rro r(e rtyp ) else
i f jr. ty p a rrays then e m u l( 2 2 ^ ta b { x . r e f\. m e )
end else i f x . t y p O n o t y p (hen erro r(ertyp );

P R O C R A M L ISTIN G

SECT. A .8

147

end else
begin (va ria b le p a ra m e ter )
I f s y < > id e m Ihen erro r(e rid ) else
begin k := lo c (id ); in s y m b o i,
I f k < > 0 then
begin i f ia t[ k ). o b j < > variable then error(erpar),
x . ty p := tub[k]. ty p ; x . r e f : - tab[k]. ref;
i f ta b { k \ n o r m a l then em it2(Q , ta b [k]. le v , tab[k].
ad r)
else e m if2 ( \, iab{k]. le v , lab[k}. adr);
i t s y mlb ra ck then
se le c to r (fs y s + [ c o m m a , c o lo n , rparenl], * ) ;
i f (jt. ty p < > ta b [c p ], ty p ) o r (x. r e f< > ta b [c p ). ref)
then error(ertyp)
end
end
end
end;
te st([c o m m a , rparent], f s y s , e r key );
u n til s y < > co m m a ;
If 5y - rparenl then in s y m b o i else erro r(erp u n )
end;
i f c p < la s tp then e r r o r ( e r p a r ) ; ( * to o f e w aclt4al p a r a m e te r s * )
c m i t l ( \ 9 , b ta b [ta b [ i] . r e f] , p s i z e - 1) ;

if
end ( * c a ll ) ;

< le v e l then e m i t 2 ( 5 ,

le v , le v e l)

function resu lttyp e(a , b\ types): types;


begin
I f (a > in ts) o r (b > in ts) Ihen
begin e rror(ertyp); resulttype := n o ly p
end else
I f (a - n o t y p ) o r ( b * n o ty p ) then restdttype :m n o ty p else
resulttype := inis
end (* resuhtype*);
procedure expression;
var y: h e m ; op: sy m b o l;
procedure sim p lee xp ressio n (fsys: sym se t; var x: ite m ),
var y: item ; op: sy m b o l;
procedure term (fsys: sym se t; va r x : item );
va r y : item ; op: s y m b o l; ts: typsei;

P R O C R A M LISTIN G

IM P L M liN T A T IO N K IT
APPEN D IX

end else
i f sy * n o ts y Ihen
begin in sy m b o i, fa c t or (fs y s , *);
i f x . ty p m b o o ls then *m if(3 5 ) else
i f x . t y p O n o t y p then erro r(ertyp )

begin (fa c to r* ) x . ty p
n o ty p ; x . r e f := 0;
tesi(facbegsys, fs y s , er p u n );
w hile s y in fu c b eg sys do
begin
i f s y id e m then

end;
te st(fsys, fa c b e g sy s, erkey );

begin i l o c ( i d ) ; in sy m b o i,
w ilh tab[i) do
case o b j o f

end (* w hile*)
end (*factor*);

ko n sta n t: begin x . ty p ;= typ; x . r e f :* 0;


e m it\( 2 4 , adr)
end;
variable: begin x . ty p := typ; x . r e f: = ref,
i t s y = Ibrack Ihen
1;

i f x . ty p in sta n ly p s (hen em it(3 4 )


end else
begin
i f x . ty p in sta n ly p s Ihen
i f n o r m a l Ihen / :
else

1 else / : = 2

i f n o r m a l Ihen / :
e m it2 (f, le v, adr)
end

0 e l s c / : = 1;

end;
<>pe\, p ro ze d u re : erro r(e rtyp ),
fu n k tio n : begin x . ty p := ty p ;
i f le v < > 0 Ihen caU (fsys, i)
else em it 1(8. a d r)
end
end (*case, w ith*)
end else
i f s y in [charcon, in ico n ] then
begin i f s y charcon then x . typ : = chars
else x . ty p
e m itl (24, in u m );
* r e f : = 0; in s y m b o i
end else
I f s y = Iparent then

inis;

14 9

A.B
begin in sym b o i; exp ressio n (fsys+ [rp a ren t], x);
i f s y * rp a ren t then in sy m b o i else erro r(erp u n )

procedure fa c to rifsy s: sy m se t\ var x: item );


va r /. / : integer,

begin i f n o r m a l then / : = 0 else / : *


e m it2 (f, le v a d r);
selector {fsys, * ) ;

SECT.

begin (* ierm * )
fa c to r (fs y s + [tim e s , id iv , im o d , a n d s y ], x );
w hile sy in
id iv , im o d , a n d s y } do
begin o p ;= s y \ in s y m b o i,
fa c to r ifs y s + [ tim e s , id iv , im o d , a n d sy], y ) ;
i f o p tim e s then
begin x . ty p : resu lttyp e(x. ty p , y . ty p )i
i f jr. ty p in ts then e m it ( S l)
end else
i f o p * a n d sy then
begin i f (x . ty p ^ b o o l s ) and (y . ty p - b o o ls ) Ihen
em it{5 6 ) else
begin I f (x. t y p O n o t y p ) and (y. t y p O n o t y p )
then e rro r(ertyp );
x . typ : * n o ty p
end
end else
begin (* o p in [ id iv , im o d ]* )
i f (*. ty p o in ts ) and (y. ty p i n i s ) Ihen
i f o p ^ i d i v then e m if(58)
else e m it( 59) else
begin i f (jr. t y p O n o t y p ) and (y. t y p O n o t y p ) then
e rro r(ertyp );
x . ty p : n o ty p
end
end
end
end (*term *);
begin (sim p lee xp re ssio n * )
i f s y in [p lu s, m in u s] then

1 50

IMPLEMENTATION KIT

begin o p : sy\ insym bol;


term (fsys+[plus, m inus), x);
i f x. typ > inis (hen error(ertyp) else
i f o p m inus (hen em it(36)
end else
term(fsys[plus, m inus, orsy], x);
while sy in [plus, m inus, orsy] do
begin op : fy ; insymbol',
term (fsys+[plus, m inus, orsy), y);
if op orsy then
begin
If (x. ty p -b o o ls ) and (y. ty p -b o o ts ) then e m it(S l) else
begin i f (x . t y p o n o t y p ) and (y. ty p O n o t y p ) then
error(ertyp);
x . typ : notyp
end
end else
begin x. typ : resulttype(x. typ, y . typ);
if x. t y p * ints then If op plus (hen em it(52)
else em it(53)
end
end
end (simpleexpression*);

begin (expression*);
sim pleexpression(fsys+[eql, neq, Iss, leq, gtr, geq], x);
i f sy In [eql, neq, Iss, leq, gtr, geq] then
begin op := sy; insymbol] sim pleexpression(fsys, y);
If (x. typ in [notyp, ints, bools, chars])
and (x. typ y. typ) (hen
case op of
eql: emit(A5);
neq: em it(A6);
Iss: emit(A7);
leq: emit(AS);
gtr: emit(A9);
geq: em it(50);
end
else error(ertyp);
x. typ := boots
end
end ( expression);

PROGRAM LISTING

procedure assignment(lv, ad: integer);


var x , y: item ; / : integer;
(fafcfi). 06/ in [varicWe, proztfdr<]*)
begin x. typ : *
typ; x . r e f : * //>[*). ref;
if M6[f]. norm al then f : 0 else / := 1 ;
em it2(f, Iv, ad);
i f sy B Ibrack then
selector{[becomes, eqf\+ fsys, x);
i f sy becomes then insym bol else error(erpun);
expression(fsys, y);
i f x , ty p * y. ty p then
if x. typ in stantyps then em tt(38) else
i f x. ref< > y . re f then error(erlyp) else
i f x. typ * arrays then em /fl(23, atab[x. ref\. size)
else e n o r(en yp )
end (^assignment*)-,
procedure compoundstatement;
begin insym bol;
statement&semicolon, ewJsy)+fsys);
while sy in [semicolon]+slutbegsys do
begin i f sy semicolon (hen insym bol else error(erpun)\
statement([semicolon, endsy] +fsys)
end;
If s y = endsy then insym bol else error(erkey)
end (*compoundstatement*);
procedure ifstatement;
va r x: item ; U u U2: integer;
begin insymbol;
expression(fsys+[thensy, dosyJ, x);
i f not (x. typ in [bools, notyp]) then error(ertyp);
lct : * Ic; em it( 11 ); (*jmpc*)
i f sy = thensy then insym bol else error(erkey);
statem ent(fsys+ [efcy]);
i f sy = elsesy then
begin insym bol; lc2 := Ic; *m ( 10);
code(lct). y := Ic; statement(fsys); code[(c2]. y := Ic
end
else code[lc 1). y ;= Ic
end (ifstatement*);
procedure repeatstatement;
var x: item; lct: integer;

152

IM PLEM EN TA T IO N K IT
A PPEN D IX

begin h i ; Ic;
insym boi-, statem ent([sem icoIon, u n tilsy]+ fsys);
while s y in [sem icolon)+ statbegsys do
begin {( s y sem ico lo n (hen in s y m b o i else errorierpun)sta te m e n t(\sem ico lo n , u n tilsy]+ fsys)

end;
i f s y * u n titsy then
begin in sym b o i; exp ressio n (fsys, x);
i f not (x. ty p in [b o o ls, n o ty p J) (hen error(ertyp)e tn it\ ( \ 1, Ic,)
v
end
else erro r(erkey)
end (repeatstatem etu*);
procedure w hile sta tem en t,
var x: item ; lc lc2: integer;
begin in s y m b o i, Ic, := Ic;
expression(Jsys+ [dosy], x );
i f not ( j r . ty p in [bools, n o ty p }) then erro rU rty p );
Icj : /c ;e m /7 ( ll) ;
i f sy d o s y (hen in s y m b o i else erro rierkey)sta te m e n t(fsys); e m i(l(1 0 , Ic,); code[lc2l y : /c
end (w h d esta tem en t* );
procedure fo rsta te m e n t;
var cvt: types; x: item ;
i> lc Ic,: integer;
begin in s y m b o i,
i f s y id e m then
begin i := lo c (id ); in sy m b o i,
i f i 0 then c v t : - in ts else
i f tab[i], o b j variable (hen
begin cv t := tab[i). typ;

i f s y * lo sy then
begin
in s y m b o i, expressionQdosy]-*- f s y s , * ) ;
i f jr. ty p < > cv t then erro r(ertyp )
end else sk ip ([ d o s y ] + fs y s , erkey );
lc t := Ic; em it( 14);
i f sy = d o s y then in s y m b o i else erro r(erkey);
lc2 := Ic; sta tem en t(fsys);
tm tflQ S , /c ,); code[lc,]. y
Ic
end (fo rsta te m e n t* );
procedure statidproc(n: integer);
v a r i, f: in teg er;
jr, y: item ;
begin
case n o f
1, 2: begin (*read)
i f s y = /pa ren t then
begin
repeat in s y m b o i,
i f s y < > id e m then erro r(erid ) else
begin i : lo c (id ); in sy m b o i,
i f i < > 0 then
i f lab[i]. o b j < > variable then e rro r(e rtyp ) else
begin x . ty p : tab[i]. ty p ; x . r e f := tab[i]. ref;
i f tab[i]. n o r m a l then / : = 0 else f : \ ;
e m it2 (f, tab[i]. le v, tab[i]. adr);
i f s y - Ibrack then
se le c lo r(fsy s+ [c o m m a , rparent], jr);
i f jr. ty p in [ms, ch a rs, n o ty p ] then
em it 1(27, o r d (x . ty p )) else erro r(ertyp )

i f no( tab[i). n o r m a l then e rro r(e rtyp ) else


e m it2 (0 , tab[i). lev, tab[i). adr);
end else (C|,/ ^

P R O G R A M LISTIN G

SECT. A .8

CA " J) ' hCn

begin error(ertyp); cv t := ints


end
end else s k ip ([ b tc o m e s , rosy, dosy] i-fs y s , e n d )
i f s y = b ec o m es (hen
begin in sy m b o i; exp ressio n ([to sy, d o s y ] + fs y s , * ) ;
i f jr. ty p < > cv t then error(ertyp);
end else s k ip ([ to s y , d o s y ] + fs y s , erpun);

end
end;
lest ([co m m a , rparent], fs y s , erk e y )
u n til s y < > co m m a ;
j f Sy = rp a ren t then in s y m b o i else erro r(e rp u n )
end;
i f n 2 then em 'tt(62)
end;
3, 4: begin (w rite * )
i f sy Iparetu then
begin
repeat in s y m b o i,
i f s y m strin g then

I S3

#
154

IM W .6 M tN T A T .0 N K IT

begin e m itl( 2 4 , sleng); e m itl( 2 8 , in u m ); in s y m b o l


end else
begin ex p ressio n (fsys + [co m m a , co lo n , rparent], x );
I f not (x. ty p in sta m y p s ) then erro r(ertyp );
e m it 1(29, o r d (x . ty p ))
end
u n til s y < > co m m a ;
i f s y = rparent (hen in s y m b o l else erro r(erp u n )
end;
i f n - 4 then em it(63)
end;
5, 6: (*w ait, signal*)
i t s y < > Iparent then erro r(erp u n ) else

begin in s y m b o l, i f s y < > id e n t then erro r(erid ) else


begin i : lo c (id ); in sym b o l;
I f * <~-> 0 then i f tab{t). o b j < > variable
then error(ertyp)
else
begin x . ty p := tab[i). ty p ; x . r c f : = tab[i\. ref;
i f tab[t]. n o r m a l then / : - 0 else / : - 1;
e m it2 (f, tab{i]. le v, tab{i). a d r);
i f s y = Ibrack then sctcctoH Jsys+ [ rparent) , x ) ;
i f x . typ = ints then em it(n + 1) else erro r(ertyp )
end
end;
i f s y = rparent then in s y m b o l else erro r(erp u n )
end;
end ( *case* )
end (sta n d p ro c* );
begin (sta te m e n t* )
i f s y in statbegsys+ [ident] then
case s y o f
idem : begin i : = lo c (id ); in sym b o l;
I f i < > 0 then
case tab[i]. o b j o f
k o n s ta n t, ty p e 1: error(ertyp );
variable: a ssig n m en t(ta b [i\. le v ,
adr);
prozedure:
i f tab[i). le v < > 0 then c a ll(fsys, i)
else standproc(tab[i]. a dr);
fu n k tio n :
i f tabif). r e f = display[levef] then
assignm ent(tab[i). I e v + 1, 0 ) else erro r(ertyp )
end

PR O G R A M LISTIN G

APPEN DIX

I 55

end;
beg in sy: i f id # co b eg in # then
begin em i't(4); co m p o u n d sta te m en t; em (5) end
else co m p o u n d sta te m en t;
ifsy: ifsta tem en t;
w hilesy: w hilestatem ent;
rep ea tsy: repeatstatem ent;
fo r s y : fo rsta tem en i;
end;
te st(fsys, [ J, erp u n )
end (*sta tem en t* );
begin ( b lo c k * ) d x : 5; p rt : *
i f level > Im a x then fa ta l(5 );
te st(ilp a ren t, c o lo n , se m ic o lo n ], fs y s , erp u n );
e n terb lo ck; display[level)
b ; p r b := b;
tab{prt]. ty p :m n o ty p ; tab[prt]. r e f : = p rb ;
ir (sy - Ip a ren t) and (level > 1) then para m eterlist;
b tab{prb). la stp a r := I; btab[prb]. p s iz e
d x;
i f isfu n then
i f i y - c o lo n then
begin in sy m b o l; (fu n c tio n ty p e* )
i f s y id e n t then
begin x
lo c (id )\ in sym b o l;
i f x < > 0 then
i f tab[x]. o b j < > ty p e 1 then e rro r(e rtyp ) else
i f tab[x]. ty p in s ta n typ s then tab{prt). ty p := iab{x]. typ
else erro r(ertyp )
end else sk ip ([se m ic o lo n ]+ fsy s, erid )
end else erro r(e rp u n );
i f s y - sem ico lo n then in s y m b o l else erro r(erp u n );
repeat
i f s y - co n stsy then co n sta n td ecla ra tio n;
i f Sy - ty p e sy then typedeclaration;
i f s y - va rsy then variabledeclaration;
b ta b {p rb ). vsize
d x;
w hile s y in [p ro c ed u resy, fu n c tio n sy ] do procd ecla ra tto n ;
test([b eg in sy), b lo ckb eg sys+ sta tb eg sys, e r k e y )
u n til s y in statbegsys;
tab[prt). a d r : Ic;
in sym b o l; sta te m e n t([se m ico lo n , e n d sy]+ fsys);
while s y in [se m ico lo n ]* sta tb e g sy s do
begin i f s y sem ico lo n then in s y m b o l else error(erpun);
sta te m e n td s e m ic o lo n , en d sy] + fsys)

156

IMPLEMENTATION KIT

APPENDIX

if sy * endsy Ihen im ytnbol else error(erkey);


lesi(fsys+ [period), [ ], erkey);
end (*Wt>cfc*);
(*.................................................................................................. interpret)
procedure interpret;
label 97. 98.
const
stepmax = 8;
(m ax steps before process switch)
tru t;
(integer value o f true*)
fals - 0;
(*integer value o f false*)
charI * 0;
(*lowest character ordinal*)
charh * 63;
(highest character ordinal*)
type ptype 0. pm ax;
( index over processes*)
var ir: order,
(instruction buffer*)
ps:
(processor status )
(run, fin, divchk, inxchk, stkchk, linchk, Ingchk, redchk, deadlock);
Incnt,
( num ber o f lines*)
chrcnt: integer,
(num ber o f characters in tine*)
h lt h 2, h it h,\ integer,
(local variables*)
s : arrayf 1. stm ax] of integer,
(the stack*)
(process table one entry fo r each process*)
ptab: *TT*y[j>type) of record
t.b,
(*top, bottom o f stack*)
PC,
(*program counter*)
stacksize: integer,
(*stack limit*)
display: arrayf 1. . Imax] of integer;
suspend: integer-,
(*0 or index o f semaphore*)
active: boolean
(procedure active flag*)
end;
npr,
(num ber o f concurrent processes*)
curpr: ptype;
(current process executing )
stepcount: integer;
(num ber o f steps before switch*)
seed: integer;
(random seed*)
pflag: boolean;
(concurrent call flag*)
procedure setran(seed: integer); extern;
function ran: real, extern;
procedure chooseproc;
(from a random starting point search fo r a process that is active and not
suspended, d aborts the interpreter i f a deadlock occurs.*)
var d: integer;

SECT. A.8

PROGRAM LISTING

begin d :*= p m a x + l;
curpr :* (curpr+trunc(ran*pmax)) mod (pmax + 1);
while ((not ptab[curpr]. active)
or (ptab[curpr\ s u s p e n d o ))
and (d > 0) do
begin d : d - 1; curpr :* (curpr* I ) mod (pmax-H ) end;
if d < 0 then
begin ps : deadlock; goto 98 end
else rtepcou/tl := trunc(ran stepmax)
end;
(functions lo convert integers to booleans and conversely*)

function itob(i: integer): boolean;


begin if i tru then itob: "tru e else itob: = false end;
function btoi(b: boolean): integer;
begin if b then btoi:
else bioi: fals end;
begin (^interpret*)
3 (1 ]:* 0; s[2]
0 ;* [3 ]: = - l ; s [ 4 ]
btab[ 1]. last;
with pfab{0] do begin
b :* 0; suspend : = 0 disploy[ 1 ] : 0;
t : bfub[2) vsizc - 1; p c :=*
aciive:^true; stacksize := stmax - pmax*sikincr
end;
for curpr : 1 to pm ax do with ptab{curpr] do
begin acftV* :** false; display[ 1] : 0; pc
0; suspend := 0
b : = p/af>[ c u r p r - 1]. jroc*.s<ztf+1; stacksize :=* b+stkincr
t : 6 - 1
end;
npr: = 0; cwrpr:0; pflag.-false;
seed : c/o<rfc;
stepcount: = 0;
p$
run; //icn/
0; cA w i/ :* 0;

repeat
if p/afr[0]. active then curpr : = 0
else if stepcount 0 then chooseproc
else f tepcount := x/epcounr - 1;
with p/a6[curpr] do begin ir : code[pc]; pc
pc + 1 end;
if pflug then
begin if ir. / 18 (marfatacA;*) then Apr : /tpr + 1;
curpr : = /ipr
end;
with ptab[curpr] do
case *>. / of

IMPLEMENTATION KIT

APPENDIX

0: begin (lo a d address*) t := /+ 1 ;


if t > stacksize then p s :m stk ch k
else s(f] : = d u p /ay [ir.x ] + ir. y
end;
1: begin (*load value*) t := t+ 1;
if / > stacksize th en p s : - stk c h k
else j{/] : * s[display[ir. *] + ir, y]
end;
2: begin (lo a d indirect) / := f+ 1;
if t > stacksize th en ps ; stkchk
else iff] : - s[s[disp!ay[ir. jr] + ir. y]]
end;
3: begin (u p d a te display )
h, : * ir. y; ft, := ir. x ; ftj : * b;
rep eat display[ht] := /,; ft, : A, I ; ft, : j( /i,+ 2)
until h , - A,
end;
4: (cobegin*) p flag := frue;
5: (co*/id*) begin
:= fa lse , ptab[0]. active : * /are end;
6: begin ( kvw*)

A,

s[<);I: f - 1;

if jfft,] > 0 then jfA j) : *[A,J - I


else begin
: f t,; stepcount := 0 end
end;
7: begin (;ig /ia/ )
*(*]1
* 1; A, := p m a x + 1 ; Aj : trunc(ran*hz)\
while (ft, > * 0 ) an d (ptab{h>]. su sp en d < > ft,) do
begin h i
(ft*+ 1) m od ( p m a x + 1); A, : * A, - 1 end;
if f t,< 0 then j(A|1 := a{A ,J+l else p tab[hi). su sp en d :*= 0
end;
8: case ir. y of
17: begin t
f+ 1 ;
if / > stacksize then p s : 33 stkchk
else j{/] : b to i(e o f(m p u t))
end;
18: begin t : = /+ 1 ;
if t > stacksize then p s : stk ch k
else if/J : =* b(oi(eoin (input))
en d ;
end;
10: p c : ir. y; (ju m p * )
11: begin (*conditional ju m p * )
If iff) fa ls then p c := ir. y \ t : * t - l

P R O C R A M U S TING

SECT. A.*

14: begin (*for\up) A, := 4*- 1 !;


if A, < * 4 0 then 4 4 * 2]] : A, else
begin / ; 7 -3 ; p c :m ir. y
end
end;
15: begin (for2up) h2
4 , - 2]; h x := s(h2) + J;
if/?, < = 4 0 then
begin sJr2] : A, ; pc := ir. y end
else / :** (-3 ;
end;
18: begin A, i^btabitabiir. y]. ref], vsize;
if t+ h | > stacksize then py
stkchk eke
begin / := f+5; 4*~1) := A , - l ; 4 0 *
y
end

end,
19: begin active := true; h x
t - i r . y;
h t :m j(A, + 4J; (*hi points to tab*)
A, :** to6{A3]. lev; dup/ay(Aj+l] : A,;
h t :* 4 * i + 3] + *ii
4*1+1]
pc; 4 *1 + 2]
dispfayihj;
if pflag then 4*i+ 3) :* ptab[0]. b else sf./** + 3] : b;
for A3 := r + 1 to h 4 do 4A>)
0;
b
A,; i :* h4; pc : /ab{Aj]. adr
end;
21: begin ()</) ht :* ir. y; (*A, points to atab*)
A* := Qtab[hx). low; A, :* 40;
if /ij < A2 then ps :* mxcAA else
i f fts > afafi[hx]. high then p s : inxchk else
begin t : / - I ; 40 := 40 + (A>-A2)flMA{A,).
end
end;
22: begin (Wood block*) h x
4 0 ; t * 1;
A, : ** ir. y + t; it h 2 > stacksize then ps : stkchk else
while / < />3 do
b e g in f : *

/+1;40 := 4*tl; * i

*+*

end
end;
23: begin (*copy block*) A,
4* I];
Ai
4 0 : *j
*i + ir- y\
while At < A} do
begin 4*i] * 4**1; *i :* * i+ l; *i :* *+1
end;
f := t - 2
end;

ISV

160

IM PLEM EN T A TIO N KIT

A PPE N D IX

24: begin (litera l* ) I : /+ 1 ;


i f t > sta cksize then p s
s tk c h k else 4 0 := ir. y
end;
27: begin (*read*)
i f c o f(in p u i) then p s := red ch k else
case ir. y o f
1: read(s[s{t]});
3: begin rea d (ch ); 441J] := o rd (ch ) end;
end;
/ := t - l
end;
28: begin (w r ite string*)
h,
j( 0 ; h t : ir. y ; / : = f - 1 ;
c h r c n t c h r c n t + h , ; i f ch rcn t > lineleng (hen p s := Ingchk;
repeat w rite(stab[h2)); h l := /,] ; h 2
h 2+ [
u n til h t * 0
end;
29: begin ( w r ite l )
i f ir. y - 3 Ihen h , := 1 else A, := 10;
chrcnt ; cA rc/+A,;
i f ch rcn t > lineleng then p s : * In g ch k else
case ir. y o f
1: w /7fe(40);
2: ttW *(i/e6(40));
3: i f (^[?]<c/?ar/) o r ( fy \> c h a r h ) then p s : inxc'-.K
else yvriie(chr(s{t]))
end;
t
f-1
end;
31: p j : = /m ;
32: t : 6 - l ; p c
f[6 + l];
i f p c < > 0 then b : * 4 ^ + 3 ] else
begin n p r := n p r - 1; ac/iVc : /<*/;
step c o u n t ;= 0; pwi>[0]. ac//Ve ; (n p r = 0)
end
end;
33: begin (* exit fu n c tio n * )
t := 6; p c := 4 6 + 1 ) ; b := 4Z> + 3]
end;
34: j[/J
4 4 r]];
35: 4 0 : fw (n o t(/7 o t(4 0 )));

36: sfrj :=
38: begin (*store*) 4 4 / - ] ] ] := j [ / ] ; i

t - 2 end;

S E C . A .8

P R O G R A M LISTIN G

161

45: begin / := f - 1 ; 4 0
*'< ( 4 0 4 '+ ! ] ) ndi
46: begin t := < -1 ; 4 0 : = *> M 4 0 < > 4 + l] ) n d .
47: begin t := i - l ; 4 0
i>fo(40 < 4 * + l))
48: begin t
/ - l ; 4 0 : fcw(40
4 < + U ) e nd>
49: begin / : - < -1 ; 4 0
&m<4 0 > 4 ' + U) end:
50: begin / := f - 1 ; 4 0 135 & (40 > 4 * + !]) nd;
51: begin t :* / - l ; 4 0
btoi(itob(s[t]) o r Uob(s[t+1]) ) end;
52: begin t :m f - 1 ; 4 0
4 0 + 4 '+ l ] e ndi
53: begin t
/ - l ; 4 0 := 4 0
4*+ 1 l t n d >
56: begin / := f - 1 ; 4 0 := btoi(iiob(s[i]) and itob(s[l+ 1])) end;
57: begin t := f - 1 ; 4 0 := 4 0
* 4 ' + l] e n d *
58: begin t i
f-1 ;
if 4 r + l ] 0 then ps := divchk ebe
4 0 := 4 0 div 4 < + l]
end;
59: begin t : / - l ;
If 4 r + l ] 0 then ps
divchk else
4 0 := 4 0 mod 4#+ )
end;
62: if eoJ\inpui) then p s : redchk else readln;
63: begin writeln; In c n t: Incnt + 1; chrcnt :** 0;
if Incnt > linelimtt then ps := linchk
end
end (*c<w**);
until ps < > rim ;
98: writeln;
if ps < > fin then
begin
with ptab{curpr\ do
write(ffOhah a t# ,p c : 5 ,# in process# , curpr: 4, tt because o f # ) ;
case ps of
deadlock: writeln(# deadlock#);
divchk: w riteln(# division by 0 0 ) ;
inxchk: write!n(# invalid index#);
stkchk: writeln(#storage overflow #);
linchk: w riteln(#too m uch output#);
Ingchk: writeln(#line too long#);
redchk: w riteln(# reading past end o f file # );
end;
writeln(#Qprocess active suspend p c # );
for h t := 0 to pm ax do with piab[ht] do
w riteln (# 0 # , h t : 4, active, suspend, pc);
writeln(#0global variables#);

162

IM P l E M bN T A T IO N K IT

fo r /,
btab{ 1). last + 1 to (m ax do
w ith ta t^ h ,] do I f le v < > 1 (hen goto 97
else I f o b j m variable then i f typ in sta n ty p s then
case ty p o f
ints: w rite ln (n a m ettt tt j[ a d r \) ;
bools: w riteln(nam e tt f ~ ft , itob(s[adr]));
chars: w r ite ln (n a m e ,# = f t , c h r (^ a d r ) mod 6 4 ));
end;
97: writeln
end (*interpret*);

m a m *

begin (* m a in )
n ie ssa g e(tt - co n cu rren t
key{ 1] : # a n d
key[ 3} := tt begin
key[ 5] : ft c o e n d
key{ 7]
tt d iv
key[ 9] : = ft else
ttfo r
k 'A n ]
k e y [ 13J : - t t i f
M 13J :*= ttn o t
k e y [l7 )
Hot
k e y [ 19] := tt pro g ra m
# then
*^21]
k e y f23] := # ty p e
key{2 5 ] ; = tt var
1] : andsy;
3] := b e g in sy ;
k s y [ 5] : endsy;
7] : *
ksy[ 9 ] : *
A^>{11] :
* J > {!3 ]
fa y { l5 ] :
As>( 17} :
Auyf 19J :
**>{21} : =
ksy{2 3 ]
ksy[2$] :=

idiv;
elsesy ;
fo r s y ;
ifsy;
noisy;
orsy;
pro g ra m sy,
thensy;
lypesy;
varsy;

p a sca l-stt);
tt
tt
tt
it
ft

ke y{ 2 ] :=e tta rr a y
it
ke y[ 4 ) :- * tt co b eg in tt
tt
k*A 6] : # co n st
ke y[ 8] :* *
tt
key[lO ) := c tt e n d
tt
k e y [ 12]: 1 tt fu n c tio n tt
ke y[ 1 4 ]:* ft m o d
tt
key[ 16] : t t o f
tt
*<>>[18]:- t t p ro ced u re tt
ke y[20] :* tt rep ea t
tt
tt
* 0 * 2 2 ] := f t to
*0*24] : tt u n til
tt
key[2 6 ]: tt w h ile
tt
ksy[ 2)
arraysy;
4]
beginsy;
ksy[ 6]
constsy;
ksy[ 8] :* d o sy;
k s y [ 10)
endsy;
ksy{ 12]
fu n c tio n s y ;
k s A 14]
im o d ;
Jb>{16) : o fsy;
*f*{18] p ro ced u resy;
repeatsy;
A*>{20]
k s r f2 2 \ : tosy;
ksy{2*\
untilsy;
ksy[26] : = whUesy;

SECT. A l

PR O G R AM LISTING

sp s[# + # ) p l u s \

s p s {tt-tt]\ =

s p s{# (# )

ip ij# )# )

Ip a re n t;

sp s{# = # ]

e q l;

s p s [ t t [ # ) to ra c *;

sp s{# ,# ] :=

com m a;

s p s{# }# \ :=

rbrack\

n eq ;

s p s{# & # ]

s p s { U ;t i) :

s e m ic o lo n ;

s p s[# * # ]

c o n stb eg sys : m
typ eb eg sy s :
b lo c k b e g s y s

m in u s ;
rp a ren t;

:=

fp if# " tfj : *

163

: *

andsy;
lim e s ;

{ p lu s , m in u s , in t c o n , c h a r c o n , id e n t];
[ i d e n t , a r r a y s y J;
[c o /u tty , t y p e s y , v a r s y , p r o c e d u r e s y , fu n c t io n s y ,

: *

b e g in s y ];
fa c b e g s y s : =

[ w /c o /i, c h a r c o n , id e n t , Ip a r e n t , n o t s y ];

sta tb eg sys

[b e g m s y , i /j y , w h ile s y , r e p e a t s y , f o r s y ] ;

sta n ty p s

[ n o t y p , in t s , b o o ls , c h a r s ];

0 ; I

errp o s

:=

0 ;

t :=

I; a

Ic

0 ; cc : =

:=

c //s p /a y { 0 ] :
s k ip fla g
Ifs y

:
0 ; 6

0 ; ch

[ ); in s y m b o l;
:=

I ;

: 0 ; c2 :=

0 ;

1;

/in to ;

< >

p r o g r a m s y t h e n e,r / -t > r ( e r J t y ) e l s e

b e g in i n s y m b o l ;
ifs y

< >

id e m

I h e n e r r o r ( e r i d ) e ls e

b e g in p r o g n a m e

id ; in s y m b o l; end

end:

en te r{#

tt.

v a r ia b le , n o t y p , 0 ); ( s e n t in e l* )

e n te r (fffa b e

tt.

k o n s t a n t , b o o ls , 0 );

en ter(# tru e

tt.

k o n s ta n t, b o o ls ,

en ter(# c h a r

tt.

ty p e 1 , c h a rs,

1 );

e n t e i i # b o o le a n

tt.

ty p e 1 , b o o b ,

1 );

e n t e r ( ff in t e g e r

tt.

ty p e 1 , in is ,

en ter(# eo f

# ,

fu n k t io n , b o o b ,

1 7 );

en ter(tteo U \

tt.

fu n k t io n , b o o b ,

1 8 );

en te r(# re a d

tt,

p r o z e d u r e , n o t y p , 1);

e n te r (tf r e a d ln

tt,

p r o z e d u r e , n o t y p , 2 );

e n t e r ( # w r it e

tt.

p r o z e d u r e , n o t y p , 3 );

e n t e r ( # w r it e ln

tt.

p r o z e d u r e , n o t y p , 4 );

e n te r {# w a it

#>

e n te r (ffs ig n a l

tt.

p r o z e d u r e , n o t y p , 6 );

e n ter(#

tt.

p r o z e d u r e , n o t y p , 0 );

w ith

1 );

1 );

p r o z e d u r e , n o t y p , 5 );

6 ra 6 [ l ] d o

b e g i n l a s t ::
end;

t ; l a s t p a r ;: =

1 ; p s iz e

:=

0 ; v s iz e : =

ff

164

IM KLKM EN TATIO N K IT

AP]

block(blockbegsys+ statbegsys, false, 1);


if sy < > period (hen error(erpun);
if
vsne > stm a x -stktn c r * pm ax then error(erln);
<rm//(3l); (*hall*)
If not eof(input) then readln;
if errs ~ [ ] (hen interpret else errormsg-,
99: writeln
end.

Vous aimerez peut-être aussi