280 likes | 409 Views
Communicating Sequential Processes. Based on: C. A. R. Hoare, Communicating Sequential Processes, CACM, 21(8):666-677, November, 1978. 1. 1. 1. 1. Outline. Background and motivation Concepts and notation Examples. 2. 2. 2. 2. Background. Imperative programming models
E N D
Communicating Sequential Processes Based on: C. A. R. Hoare, Communicating Sequential Processes, CACM, 21(8):666-677, November, 1978. 1 1 1 1
Outline • Background and motivation • Concepts and notation • Examples 2 2 2 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 3 3 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 4 4 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 5 5 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 ] ] ]
Outline Background and motivation Concepts and notation Basic and structured statements Examples 7 7 7 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>
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>
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>
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?
Assignment • Simple vs. structured value • 0, true, 10 + y, x + y, … • (10, 20), (x, y), point(10, 20), done() • Signal: structured value with no component • Q: Why structured values? c(e1, e2, …, en) <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>}
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
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?
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>}
Example 1. cardreader?cardimage 2. lineprinter!lineimage 3. X?(x, y) 4. DIV!(3*a + b, 13) Q: if 3 and 4 correspond? 5. console(i)?c 6. console(j - 1)!“A” 7. X(i)?V() 8. sem!P()
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>
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.
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>
Exercise • Write a process that finds a maximum value of an array. • Write a process that performs a binary search on a sorted array.
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]
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]
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?
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()
Exercise Extend the set ADT to introduce two new operations S!remove(x) S!least(); …; x: integer; [S?x … use x … [] S?noneleft() …]
Exercise Define a bounded stack ADT by providing typical stack operations such as push, pop, top, and isEmpty.
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 …]
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]