Comput. Lang. Vol. 14, No. 4, pp. 255-262, 1989 Printed in Great Britain. All rights reserved
AN
0096-0551/89 $3.00 + 0.00 Copyright ~ 1989 Pergamon Press pie
SR APPROACH
TO MULTIWAY
MICHAEL COFFIN 1 a n d RONALD
RENDEZVOUS
A. OLSSON 2
~Department of Computer Science, University of Arizona, Tucson, AZ 85721 U.S.A. 2Division of Computer Science, University of California, Davis, CA 95616 U.S.A.
(Received 7 February 1989; revision received 10 April 1989) A~tract--This paper presents a new approach to programming multiway rendezvous problems in the SR language. The approach uses SR's concurrent invocation statement and rendezvous mechanism to coordinate the interacting processes. This approach is compared with one that suggested an extension to SR's rendezvous mechanism. The two approaches result in differing program structure. The new approach is shown to lead to simpler and cleaner interfaces between the main process and the worker processes, and uses only existing language mechanisms. The results are of importance to both programmers and designers of concurrent program languages. Concurrent programming languages dezvous Rendezvous
Concurrent programming
Synchronization Multiway ren-
1. INTRODUCTION
A rendezvous is a "meeting" between two processes. It involves three phases: first the two processes synchronize, then some communication and computation takes place, and finally the two processes go their separate ways. The rendezvous, as provided in CSP [1], Ada [2], and SR [3], has proven to be a powerful and convenient method of combining communication and synchronization in those languages. Both synchronization and communication, separately, have been generalized to multiple processes; examples include barriers, broadcast, and multicast (see, e.g. [4-7]). In this vein, Charlesworth proposes the multiway rendezvous [8], a generalization of rendezvous in which more than two processes participate. He proposes a language-independent construct--the compact--for expressing multiway rendezvous, illustrates its utility with several examples, and describes extensions to existing languages for supporting the compact. In this paper, we show how multiway rendezvous can be expressed using existing mechanisms in the newest version of the SR programming language [3]. Our particular approach employs SR's concurrent invocation statement (co) and rendezvous mechanism to achieve the desired functionality. This approach has two main advantages compared with that suggested in [8]. First, it leads to simpler and cleaner interfaces between processes involved in a multiway rendezvous. Second, it can be effected using existing language mechanisms. These results should be of interest to both programmers and language designers since the basic issue this paper addresses is how language mechanisms affect the structure of programs. The remainder of this paper is organized as follows. Section 2 gives a brief overview of relevant mechanisms in SR. Section 3 discusses Charlesworth's compact approach to multiway rendezvous, including how it can be expressed using his proposed extension of SR's input statement. Section 4 describes our approach to expressing multiway rendezvous using co statements and illustrates it with two problems. Finally, Section 5 compares our approach with Charlesworth's. Throughout this paper, we use two sample problems--what we call the plotting problem and the linear system problem--from [8] so that direct comparisons can be made. The plotting problem (example, 3.1 in [8]) uses three separate processes to compute new X, Y, and Z coordinates of a moving point, and a fourth process to calculate the planar projection and to initiate plotting the point. The linear system problem (example 3.2 in [8]) uses Jacobi iteration to solve a system of linear equations of order N using N processes. 2. SR OVERVIEW The examples in this paper employ only a subset of SR. In particular, the examples are each written as a single resource (SR's unit of modularization). Thus, we focus below on only the CL 144--C
255
256
MICHAEL COFFINand RONALDA. OLSSON
relevant aspects of SR's synchronization mechanisms• See [9] and [3] for a complete description of the language and for some examples. Synchronization in SR centers around the operation. An operation can be considered a generalization of a procedure: it has a name, and can take parameters and return a result. Operations are declared in op declarations, which specify the name of the operation, the types of its parameters and how they are passed, and the type of its return value, if any. Parameters are passed by value (val, the default), result (res), or value/result (var). An operation is serviced in one of two different ways--by a proc or by in statements--and can be invoked in two ways---call and send. A proc resembles a conventional procedure in having parameters and a body, but invoking a proc causes a new process to be created to service that invocation.t It is often convenient to have some processes started automatically when a resource is created. Such "background" processes are written using a special form of proc, specified by the keyword process instead of proe. The other way to service an operation is to employ in statements, which have the general form: in opname~ (parameters) [returns id]---~block~
opnamen (parameters) [returns id] ~ blockn ni
A process executing an in statement is delayed until at least one of the named operations has a pending invocation. Then, the oldest invocation is selected and the corresponding block is executed; the in statement terminates when that block terminates. The in statement has one additional form that is particularly convenient: receive opname(variables) is simply an abbreviation for in opname(parameters)--,variables :=parameters ni
Thus, receive corresponds closely to the traditional blocking receive statement found in languages based on message-passing. An operation is invoked explicitly using a call or send statement: call op_denotation(arguments) send op_denotation(arguments) where the operation is denoted by name if the statement is in the operation's scope, or by a capability, which is in effect a pointer to an operation. An operation is invoked implicitly when op_denotation(arguments) appears within an expression; such an invocation is semantically similar to that in a call statement• Execution of a call invocation terminates once the operation has been executed and a result, if any, returned. Execution of a send invocation, on the other hand, terminates when the target process has been created (if a proc), or when the arguments have been queued for the process servicing the operation (if an in statement). The effects of executing the various combinations of call/send and proe/in are summarized in Table 1. An additional synchronization statement, reply, facilitates programming c o n v e r s a t i o n s . Execution of reply causes the call invocation being serviced by an enclosing in statement or proc to terminate. Return values, if any, are transmitted back to the calling process, which then continues after the call invocation. The process executing reply continues with the next statement. tSome call invocations of procs are optimized to use conventional procedure calls. See [3] for details. Table 1. Effectsof invokingand servicingoperations. lnt'ocation
Service
Effect
call
proe in
Procedurecall Rendezvous Dynamicprocesscreation Asynchronous messagepassing
call
send send
proc in
An SR approach to multiway rendezvous
257
SR's co statement supports concurrent invocations. Its basic form is co concurrent_invocation//concurrent_invocation // ... oc A concurrent invocation is a call or send statement, or an assignment statement that invokes a user-defined function. Execution of co starts all invocations; the co statement terminates when all the invocations have terminated. A concurrent invocation in co can also be preceded by a quantifier, which specifies multiple invocations, one for each iteration of the implied loop. For example, a replicated file might be updated by executing co (i ,=1 to N) call
update[i](values) oe
where update is an array of capabilities containing one entry for each copy of the file to be updated. Although not shown above, code can be associated with each concurrent invocation in the co statement; such code is executed when the associated invocation completes, and can terminate the co statement early. 3. M U L T I W A Y
RENDEZVOUS
USING THE COMPACT
The examples given in [8] use compacts to express multiway rendezvous; each consists of three parts: • A main body, which uses cobegin to start all the workers and waits for them to finish. • The workers themselves, each of which executes rounds of computation, i.e. each worker process has the form initialize loop until done: perform a local computation rendezvous and share results end loop • A compact, which specifies the way values are shared and which may perform inter-round calculations. Existing concurrent languages do not provide multiway rendezvous in its natural form. However, such languages might be extended as discussed by Charlesworth in [8]. His proposed extension to the original version of SR [10], which we denote SR0, permits multiple operations to be specified in a single arm of an input statement. For example, in
opl(...), op2(...)--~block
ni
means that the process executing the input statement is delayed until opl and op2 each has a pending invocation.+ Using such a multiple-operation input statement, the worker/compact model can be easily expressed. Specifically, the main body and compact can be represented by a single process, which uses a multiple-operation input statement to rendezvous with the worker processes. Its general form is thus create worker processes if necessary initialize loop until done: use a multiple-operation input statement to receive and share results perform between-round calculations end loop Each worker process calls a unique operation in the input statement to share results. Its general form is therefore identical to that shown for workers above.
tA comma is used to separate multiple operations in this paper rather than the keyword and--as in [8]--to avoid potential confusion with the synchronization expression, which is introduced syntactically by and in both SR0 and SR.
258
MICHAEL COFFIN and RONALD A. OLSSON
To illustrate how the worker/compact model can be expressed using multiple-operation input statements, consider the solution to the plotting problem given in Fig. 1. It is written in SR extended with multiple-operation input statements. In Fig. l, each worker process calls init to obtain the initial coordinates of the point, which are passed back through result parameters. After performing some calculation, each worker calls a correspondingly named entry operation in the main process to share results. The main process uses a multiple-operation input statement to service these operations. The body of the input statement simply copies values to be transmitted back to the workers. Note that in the declaration of each entry operation, a value parameter specifies which coordinate each worker is contributing and result parameters specify which coordinates each worker needs back. For example, since x_worker contributes the X coordinate and needs to obtain new Y and Z coordinates, the declaration of x_entry specifies x as a value parameter and y and z as result parameters. Also note that the plotting problem does not require any between-round calculation; if it did, such code would appear within the input statement that services the entry operations. resource Plotting() up init(res ix,iy,iz: real) op x_entry(val xx:real; res xy:real; res xz:reai) op y_entry(res yx :real; vai yy :real; res yz :real) op z_entry(res zx:real; res zy:real; val zz:real) op proj_entry(res px,py,pz: real) process main vat x,y,z: real
read( x,y,z ) # give the initial values of x, y, and z # to all worker processes, including projection. fa k : = l to 4--, in init(ix,iy,iz )---~
ix,=x; iy:=y; iz,=z ni af do true---~ in x_entry(xx,xy,xz ),
y_entry (yx,yy,yz), z_entry(zx,zy,zz ), proj_entry (px,py,pz )--* # distribute new values
yx,=xx; zx.=xx; px,=xx xy.=yy; zy,=yy; p y , = y y xz ,=zz; yz ,=zz; pz ,=zz ni od end process x_worker var x,y,z~ real # obtain initial point. call init(x,y,z ) do true---, # compute new value of x from values of x, y, and z. # share value of new x and obtain new values for y and z. call x_entry(x,y,z ) od end
# y_worker and z_worker are similar to x_worker process projection var x,y,z: real # obtain initial point call init (x,y ,z ) do t r u e - * # compute planar projection and plot point. # ol~tain new values for x, y, and z. call proj_entry(x,y,z ) od end end Plotting
Fig. I. Multiple-operation input statement solution to the plotting problem.
An SR approach to multiway rendezvous
4. M U L T I W A Y R E N D E Z V O U S
259
U S I N G T H E CO S T A T E M E N T
The current version of SR provides an alternative way to formulate algorithms that use multiway rendezvous. Using its eo statement, a technique in which the flow of messages is essentially reversed can be used. The components of this solution are • The main body, which invokes the workers' operations, waits for them to finish (in non-deterministic order), and then re-invokes them. Thus, the main body has the form create worker processes if necessary initialize loop until done eo invoke worker_operationl / / i n v o k e worker_operation2
//... oe
perform between-round calculations end loop • The workers, which have the general form initialize loop until done--~ wait for invocation do local computation return results end loop Note that the worker processes need to be created, which requires explicit invocation from the main body (as indicated above) or use of SR's background process notation. To illustrate the co statement approach, we present solutions to the plotting problem and the linear systems problem. (More detailed SR solutions to all examples in [8] appear in [11].) The co statement solution to the plotting problem, shown in Fig. 2, reverses the direction of message exchanges. Workers are now sent new values of x, y, and z as they become awailable. The interface between the workers and main, which serves the role of a compact, in Fig. 2 is different from that when a multiple-operation input statement is used as in Fig. 1. Within the Plotting resource, main uses a co statement to send values of x, y, and z to the other processes and then delays until the worker processes pass back new values for x, y, and z and the projection process has plotted the point. Note that each all operation uses only value parameters and a return value. The second example demonstrates the eo statement approach to the linear system problem. Our solution, shown in Fig. 3, uses workers as servers in a conventional client/server relationship. In Fig. 3, the driver process first creates N worker processes, each of which returns capabilities that are used for subsequent communications. The loop in the driver process sends to each worker the current "guess" for X and waits to receive from each worker its new guess for the corresponding element of X; the loop terminates when successive guesses for X have converged. Finally, the driver uses a co statement to inform the workers that they should terminate, and to print the final array.
5. D I S C U S S I O N Multiway rendezvous can be expressed in an SR-like language using multiple-operation input statements or using co statements. These dual approaches present several interesting tradeoffs from both the programming and linguistic viewpoints. The essential difference in the structures of resulting programs is the direction of message exchanges between the main process and the worker processes. Using multiple-operation input statements, the workers invoke operations in the main process; using eo statements, the main process invokes operations in the workers. The co statement approach results in simpler worker processes. Workers just wait for work, do it, and return the results. They return their results implicitly, i.e. as part of the actions of completing an invocation. Thus, the workers are more general purpose than their counterparts in the
260
MICHAEL COFFINand RONALDA. OLSSON resource Plotting() op all~c(val x,y,z: real) returns new_x: real op all_y(val x,y,z: real) returns new_y: real op all_z(val x,y,z: real) returns n e w - r : real op projeet(val x,y,z: real) process main vat x , y , z : real
read( x,y,z ) do true---* co x ,= all_x(x,y,z)
/ / y := all_y(x,y,z) // z := all~z(x,y,z) //project (x,y,z ) OC
od end process x_worker do true---* in a l l ~ c ( x , y , z ) returns new x # compute new_~: from values of x, y, and z nl od end
# y_worker and z_worker are similar to x_worker process projection var x,y,z: real do true---~ receive project (x,y,z) # compute planar projection and plot it. od end end Plotting Fig. 2. Concurrent invocation statement solution to the plotting problem.
resource Linear() type workercap = roe( compute: cap (X[I:N]: real) returns new_x: real; done: cap()) process driver var work[l:N]: workercap
read(A,B,X) old_l(:= X # create N workers, passing each the initial arrays and its integer 'id'. # work[i] is set to capabilities used for # subsequent communication with worker i. co (i:= 1 to N) work [i]:= worker(A,B,i) oc do true---, co (i:= 1 to N) X[i]:= work[i].compute(X) oe if " X is near old_X"---,exit fi
old_X.= X od co (i:= 1 to N) work[i].doneO//print(X) oe end proe worker(A,B,i) returns we: workercap # each worker gets its own copy of these (local) operations op compute(X[l:N]: real) returns new_x: real; op done() # assign and send back capabilities for this worker's operations.
we.compute ,= compute; we.done .= done reply # compute until told that done. do true---* in c o m p u t e ( X ) returns new_x # compute new X[i] using A, B, and X. new_x
z---- . . .
0 done()--~exit # break out of the do loop. ni od end end Fig. 3. Concurrent invocation statement solution to the linear system problem
An SR approach to multiway rendezvous
261
multiple-operation input statement approach. There, workers must explicitly invoke an operation to return results. That operation must be explicitly named in the code (as in Fig. 1) or must be a capability passed in as an additional parameter. The first alternative limits a worker to being part of a specific multiway rendezvous; the second requires an additional parameter, which complicates the interface. The difference between worker processes is readily apparent in the two solutions presented to the plotting problem (Figs 1 and 2) and more generally when the structure of workers resulting from our approach is compared with that in [8] for any of the examples. The structure of worker processes in the co statement approach, especially the fact that they implicitly return results, has another advantage. This approach allows any number of workers, configured arbitrarily, to participate in a multiway rendezvous. For example, suppose a given computation needs 20 workers, but is to run on only 10 processors. The main process can simply invoke 20 worker operations. Each of 10 worker processes, one on each processor, can then service two worker invocations per round. This structure is possible since each worker process is delayed only when waiting for work. On the other hand, such a structure is not possible in the multiple-operation input statement approach since processes invoking the operations are delayed until all processes are ready to communicate. In the solution to the plotting problem in Fig. 1, for example, x_worker delays when invoking x_entry until y_worker, z_worker, and projection have finished their computation and invoke their entry operations. In the 20 worker example above, each worker process would be delayed when trying to return results until after all worker invocations have been serviced. Hence, the number of actual worker processes must equal the number of logical workers. Two worker processes on each processor would therefore be required in this example. The multiple-operation input statement is attractive since it is the natural generalization of two-way rendezvous. Programmers should therefore have little conceptual difficulty in under'standing it or in extending programs to employ it. Furthermore, extending SR 0 with such an input statement, as proposed in [8], seems reasonable with respect to both semantics and implementation. However, extending the current version of SR with such an input statement would be more difficult. SR's input statement allows invocations of a single operation to be serviced by multiple processes. Such shared operations provide increased flexibility in programming inter-process communication (see [3] for examples). Unfortunately, such sharing would cause semantic difficulty if multiple operations on a single arm of an input statement were allowed. Suppose, for example, that process P1 contains the input statement
in a(), b() . . . .
ni
process P2 contains the input statement
in b(), c()---~.., ni and process P3 contains the input statement
in a(), c()--~.., ni Scenarios in which one of the processes is starved due to the, in effect, conspiratorial execution of the other two are easy to envision. Modifying the existing semantics of the input statement, without imposing restrictions, would be difficult. On the other hand, the co statement is already a part of SR. Since it builds on other SR features, its semantics is relatively straightforward and its implementation added only slightly to the complexity of the compiler and run-time support. The co statement also has other uses besides providing multiway rendezvous, e.g. "broadcast a request, wait for the first answer", or "broadcast a request and wait for a majority to reply". These uses rely on early termination of the co statement; the same effect cannot be achieved (at least not as directly) using the multiple-operation input statement. To summarize, SR's co statement supports multiway rendezvous interactions in a clean way. As our examples have shown, the interfaces between processes is straightforward and the structure of the worker processes is simple, yet general purpose. While SR would be a richer language if it allowed multiple-operation input statements, we do not feel the need to introduce further linguistic support for the multiway rendezvous. Designers of other concurrent programming languages
262
MICHAELCOFFINand RONALDA. OLSSON
s h o u l d c o n s i d e r the c o n c u r r e n t i n v o c a t i o n s t a t e m e n t as an alternative to a m u l t i w a y r e n d e z v o u s mechanism. 6. S U M M A R Y This p a p e r presents a new a p p r o a c h to p r o g r a m m i n g m u l t i w a y r e n d e z v o u s p r o b l e m s in the S R language. T h e a p p r o a c h uses S R ' s c o n c u r r e n t i n v o c a t i o n s t a t e m e n t a n d r e n d e z v o u s m e c h a n i s m to c o o r d i n a t e the i n t e r a c t i n g processes. This a p p r o a c h is c o m p a r e d with one p r o p o s e d by C h a r l e s w o r t h t h a t suggested an extension to S R ' s r e n d e z v o u s m e c h a n i s m . T h e two a p p r o a c h e s result in differing p r o g r a m structure. The new a p p r o a c h is shown to lead to simpler a n d cleaner interfaces between the m a i n process a n d the w o r k e r processes, a n d uses only existing l a n g u a g e m e c h a n i s m s . The results are o f i m p o r t a n c e to b o t h p r o g r a m m e r s a n d designers o f c o n c u r r e n t p r o g r a m languages. T h e p a p e r first gives a b r i e f overview o f relevant m e c h a n i s m s in SR, n a m e l y S R ' s s y n c h r o n i z a t i o n m e c h a n i s m s . Then, the p a p e r discusses C h a r l e s w o r t h ' s a p p r o a c h to m u l t i w a y rendezvous, including h o w it can be expressed using his p r o p o s e d extension o f SR. The p a p e r then describes o u r a p p r o a c h to expressing m u l t i w a y r e n d e z v o u s using S R ' s c o n c u r r e n t i n v o c a t i o n s t a t e m e n t s a n d r e n d e z v o u s m e c h a n i s m , a n d illustrates it on two p r o b l e m s . T h e key to o u r a p p r o a c h is to reverse the direction in which processes c o m m u n i c a t e , which is facilitated by S R ' s c o n c u r r e n t i n v o c a t i o n statement. E x a m p l e s are given to illustrate the two different a p p r o a c h e s . T h e p a p e r concludes with a c o m p a r i s o n o f the two a p p r o a c h e s a n d s o m e m o r e general c o m m e n t s a b o u t m u l t i w a y rendezvous. P a r t i c u l a r a t t e n t i o n is p a i d to the interface between the processes involved in the m u l t i w a y rendezvous. Acknowledgements---Greg Andrews participated in discussions about the multiway rendezvous. He, Arthur Charlesworth,
and the referees provided very useful comments on earlier drafts of this paper. REFERENCES 1. Hoare, C. A. R. Communicating sequential processes. Commun. ACM 21(8): 666~77; 1978. 2. U.S. Department of Defense, Reference Manual for the Ada Programming Language. ANSI/MIL-STD-1815A; 1983. 3. Andrews, G. R., Olsson, R. A., Coffin, M., Elshoff, I., Nilsen, K., Purdin, T. and Townsend, G. An overview of the SR language and implementation. ACM Trans. Prog. Lang. Systems 10(1): 51-86; 1988. 4. Brooks, E. D. The butterfly barrier. Int. J. Parallel Prog. 15 (4): 295-307; 1986. 5. Cheriton, D. R. and Zwaenepoel, W. One-to-many interprocess communication in the V-system. Proc. ACM Sigcomm '84 Symposium; 1984. 6. Cheriton, D. R. The V kernel: A software base for distributed systems. IEEE Software 1(2): 19~,2; 1984. 7. Liskov, B. and Scheifler, R. Guardians and actions: Linguistic support for robust, distributed programs. ACM Trans. Prog. Lang. Systems 5(3): 381-404; 1983. 8. Charlesworth, A. The multiway rendezvous. ACM Trans. Prog. Lang. Systems. 9(2): 350-366; 1987. 9. Andrews, G. R. and Olsson, R. A. Revised Report on the SR Programming Language. TR 87-27, Department of Computer Science, University of Arizona; 1987. 10. Andrews, G. R. Synchronizing resources. ACM Trans. Prog. Lang. Systems 3(4): 405-430; 1981. I I. Coffin, M. and Olsson, R. A. The SR Approach to Multiway Rendezvous. TR 88-3, Department of Computer Science, University of Arizona; and CSE-88-1, Division of Computer Science, University of California, Davis; 1988. About the Autbor--MICHAELHOWARDCOFFINreceived his B.S. in mathematics from the South Dakota
School of Mines and Technology in 1982. He received the M.S. degree in computer science from the University of Arizona in 1985, and he expects to obtain his Ph.D. from the same institution in 1989. Mr Coffin's research has focused on languages for parallel and distributed computation. He is especially interested in the design and implementation of efficient languages for general and scientific programming. Mr Coffin is a member of the Association for Computing Machinery and is a member of the special interest groups in programming languages, operating systems, and mathematical software. About the Author--RONALDARTHUROLSSONreceived the B.A. degree in mathematics and in computer
science, and the M.A. degree in mathematics, from the State University of New York, College at Potsdam in 1977. He received the M.S. degree in computer science from Cornell University in 1979 and the Ph.D. degree in computer science from the University of Arizona in 1986. Dr Olsson has been assistant professor of computer science at the University of California, Davis since 1986. His research activities center around concurrent programming languages, focusing on issues in design, implementation, optimization, and debugging. Dr Olsson is a member of the Association for Computing Machinery and its special interest groups in programming languages and operating systems.