Communicating Sequential Processes Based on: C. A. R. Hoare, Communicating Sequential Processes, CACM, 21(8):666-677, November, 1978. 1 Outline • Background and motivation • Concepts and notation • Examples 2 Background • Imperative programming models – Commands: assignment, sequence, alternative, iterative – I/O as library functions, not primitive • Concurrency and parallelism – Multi-processor disguised as mono-processor – Need for expressing concurrency explicitly – Shared memory vs. message passing 3 Motivation • New programming model based on message passing • I/O regarded as primitive constructs • Concurrency (parallel composition of processes) as fundamental structuring method => • Concurrent Sequential Processes (CSP) 4 Key Features of CSP • Dijkstra’s guarded commands – [B1 -> S1 [] B2 -> S2 ] – For introducing and controlling non-determinism (or choice) • Dijkstra’s parallel commands – [P1 || P2] – For concurrency • Input and output commands – p?x; q!x – For receiving and sending messages • Input commands in guards and repetitive commands – [p?x -> S]; *[p?x -> S] – Branching or repetition based on inputs • Simple pattern matching – For discriminating the structures of input messages and – For accessing their components 5 Example • Q: What does the process X do? X:: *[c: character; west?c [c asterisk east!c [] c asterisk west?c; [c asterisk east!asterisk; east!c c asterisk east!up_arrow ] ] ] 6 Outline Background and motivation • Concepts and notation – Basic and structured statements • Examples 7 Concepts and Notation • Commands – – – – Specify behavior of device executing the commands May have side effect (internal or external) May succeed or fail (“strict” for structured commands) Basic vs. structured • Basic: null (skip), assignment, input, output • Structured: alternative, repetitive, parallel <command> ::= <simple command> | <structured command> <simple command> ::= <null command> | <assignment command> | <input command> | <output command> <structured command> ::= <alternative command> | <repetitive command> | <parallel command> <null command> ::= skip <command list> :: {<declaration>; <command>;} <command> 8 Parallel Commands (||) • List of processes separated by || – Process: sequence of commands preceded by an optional label – E.g., [stdin?line || stdout!“hello”] • Semantics – Concurrent execution of constituent processes – All processes start simultaneously – Terminate successfully if all terminate successfully <parallel command> ::= [<process> { || <process>}] <process> ::= <process label> <command list> 9 Process • • Unit of program in CSP Sequence of commands with an optional label (Q: Why label?) – E.g., skip, X:: skip • Subscripted label to specify a series of concurrently running processes – E.g., X(1):: skip, X(i):: skip, X(i,j):: skip, X(i: 0..99):: skip – Semantics: X(i: 1..n)::CL for [X(1):: CL1 || X(2):: CL2 || … || X(n):: CLn] I.e., CLj is CL[j/i] <process> ::= <process label> <command list> <process lablel> ::= <empty> | <identifier> :: | <identifier>(<label subscript> {, <label subscript>}) :: <label subscript> ::= <integer constant> | <range> <integer constant> ::= <numeral> | <bound variable> <bound variable> ::= <identifier> <range> ::= <bound variable>:<lower bound>..<upper bound> <lower bound> ::= <integer constant> <upper bound> ::= <integer constant> 10 Example [cardreader?cardImage || lineprinter! lineimage] [west:: DISASSEMBLE || X:: SQUASH || east:: ASSEMBLE] Convention: Capitalized words for process definitions [room:: ROOM || fork(i: 0..4):: FORK || phil(i: 0..4):: PHIL] Q: How many concurrent processes? 11 Assignment • Simple vs. structured value – 0, true, 10 + y, x + y, … – (10, 20), (x, y), point(10, 20), done() c(e1, e2, …, en) • Signal: structured value with no component • Q: Why structured values? <assignment command> ::= <target variable> := <expression> <expression> ::= <simple expression> | <structured expression> <structured expression> ::= <constructor>(<expression list>) <constructor> ::= <identifier> | <empty> <expression list> ::= <empty> | <expression> {, <expression>} <target variable> ::= <simple variable> | <structured target> <structured target> ::= <constructor>(<target variable list>) <target variable list> ::= <empty> | <target variable> {, <target variable>} 12 Matching Assignment x := e c(x1, x2, …, xn) := c(e1, e2, …, en) • Fails if the value of expression is undefined or if that value doesn’t match the target variable • A simple target variable matches any value of its type. • A structured target variable matches a structured value if – they have the same constructor – they have the same number of components – Each component matches the corresponding component 13 Example 1. x := x + 1 2. (x, y) := (y, x) 3. x := cons(left, right) 4. cons(left, right) := x Q: Match? Differ from 3? 5. insert(n) := insert(2*x + 10) 6. x := P() 7. P() := x Q: Match? 8. insert(n) := has(n) Q: Match? 14 Input and Output Commands • • Specify communication between two CSPs, say P1 and P2, e.g., [P1:: x: integer; P2?x || P2:: P1!10] Communication occurs if I/O commands correspond: – The source of an input command in P1 is P2. – The destination of an output command in P2 is P1. – The target variable of the input in P1 matches the expression of the output in P2. • Semantics – Simultaneous execution of corresponding I/O commands – Effect: similar to an assignment <input command> ::= <source> ? <target variable> <output command> ::= <destination> ! <expression> <source> ::= <process name> <destination> ::= <process name> <process name> ::= <identifier> | <identifier> ( <subscripts> ) <subscripts> ::= <integer expression> {, <integer expression>} 15 Example 1. cardreader?cardimage 2. lineprinter!lineimage 3. X?(x, y) 4. DIV!(3*a + b, 13) 5. console(i)?c Q: if 3 and 4 correspond? 6. console(j - 1)!“A” 7. X(i)?V() 8. sem!P() 16 Alternative Commands • Specify execution of exactly one of its constituent guarded commands, e.g., [x y m := x [] y x m := y] • Guarded commands with ranges (i:1..n)G CL stands for G1 CL1 [] G2 CL2 [] … [] Gn CLn • Multiple guard elements with an optional input command at the end [x > 0; y: integer; user?y user!(y/x)] <alternative command> ::= [<guarded command> {[] <guarded command>}] <guarded command> ::= <guard> -> <command list> | (<range>{,<range>})<guard> -> <command list> <guard> ::= <guard list> | <guard list>; <input command> | <input command> <guard list> ::= <guard element> {; <guard element>} <guard element> ::= <boolean expression> | <declaration> 17 Exercise • Write a process that reads a number from a user and returns its sign, i.e., -1 for negative, 0 for 0, and 1 for positive. • Write a process that reads three numbers from a user and returns them sorted in ascending order. 18 Repetitive Commands • • Specify as many iterations as possible of its constituent alternative command. Terminate with no effect when all guards fails. i: integer; i := 0; *[i < size; content(i) n i := i + 1] *[c: character; west?c east!c] *[(i:1..10)continue(i); console(i)?c X!(i, c); console(i)!ack(); continue(i) := (c sign_off)] *[n: integer; X?insert(n) INSERT [] n: integer; X?has(n) SEARCH; X!(i < size)] *[X?V() val := val + 1 [] val > 0; Y?P() val := val – 1] <repetitative command> := *<alternative command> 19 Exercise • Write a process that finds a maximum value of an array. • Write a process that performs a binary search on a sorted array. 20 Example: Coroutines Read a sequence of cards of 80 characters each, and print the characters on a line printer a 125 characters per line. Each card should be followed by an extra space, and the last line should be completed with spaces if necessary. [west:: DISASSEMBLE || X:: COPY || east:: ASSEMBLE] *[cardimage: (1..80)character; cardfile?cardimage i: integer; i:= 1; *[i 80 X!cardimage(i); i := i + 1]; X!space] *[c: character; west?c east!c] lineimage:(1..125)character; i: integer; i := 1; *[c: character; X?c lineimage(i) := c; [i 124 i := i + 1 [] i = 125 lineprinter!lineimage; i = 1]]; [i = 1 skip [] i > 1 *[i 125 lineimage[i] := space; i := i + 1]; lineprinter!lineimage] 21 Example: Subroutines • Construct a process to accept a positive dividend and divisor, and to return their integer quotient and remainder. [DIV:: *[x, y: integer; X?(x, y) quot, rem: integer; quot := 0; rem := x; *[rem y rem := rem – y; quot := quot + 1]; X!(quot, rem)] • Compute a factorial by the recursive method, to a given limit. [fact(i:1..limit):: *[n: integer; fact(i - 1)?n [n = 0 fact(i - 1)!1 [] n > 0 fact(i + 1)!(n – 1); r: integer; fact(i + 1)?r; fact(i - 1)!(n * r)]] || fact(0):: USER] 22 Example: ADT • Represent a set of not more than 100 integers as a process, S, which accepts two kinds of instruction from its calling process X: – S!insert(n): insert the integer n in the set – S!has(n); …; S?b: query if n is included in the set S:: content: (0..99)integer; size: integer; size := 0; *[n: integer; X?has(n) SEARCH; X!(i < size) [] n: integer; X?insert(n) SEARCH; [i < size skip [] i = size; size < 100 content(size) := n; size := size + 1]] where SEARCH is i: integer; i := 0; *[i < size; content(i) n i := i + 1] Q: What happen if attempted to insert more than 100 elements? Q: What happen if attempted to insert a new element while the previous insertions is still being processed? 23 Example: ADT • Extend the set ADT to provide a fast method of scanning all members of the set, e.g., S!scan(); more: boolean; more := true; *[more; x: integer; S?next(x) … use x … [] more; S?noneleft() more := false] Add a third guarded command to S: … [] X?scan() i: integer; i := 0; *[i < size X!next(content(i)); i := i + 1]; X!noneleft() 24 Exercise • Extend the set ADT to introduce two new operations – S!remove(x) – S!least(); …; x: integer; [S?x … use x … [] S?noneleft() …] 25 Exercise • Define a bounded stack ADT by providing typical stack operations such as push, pop, top, and isEmpty. 26 Example: ADT • Define a set ADT by using an array of processes to achieve a high degree of parallelism. (Idea: Each has at most one value, and values kept as sorted.) S(i:1..100):: *[n: integer; S(i – 1)?has(n) S(0)!false; [] n: integer; S(i – 1)?insert(n) *[m: integer; S(i – 1)?has(m) [m n S(0)!(m = n) [] m > n S(i + 1)!has(m)] [] m: integer; S(i – 1)? insert(m) [m < n S(i + 1)!insert(n); n := m [] m = n skip [] m > n S(i + 1)!insert(m)]]] User process S(0) interacts with the processes as follows: S(1)!has(n); …; [(i:1..100)S(i)?b …] 27 Exercise • Extend the previous solution to respond to a command to yield the least element of the set and to remove it from the set. The user program will invoke the facility by a pair of commands: S(1)!least(); [x: integer; S(1)?x … use x … [] S(1)?noneleft() …] or, the user wishes to scan and empty the set, he may write: S(1)!least(); more: boolean; more := true; *[more; x: integer; S(1)? X … use x …; S(1)!least() [] more; S(1)?noneleft() more := false] 28