COP 4020 Lecture -*- Outline -*- * Message-Passing Concurrency Based in part on Peter van Roy and Seif Haridi's book, "Concepts, Techniques, and Models of Computer Programming" (MIT Press, 2004), and Joe Armstrong's book "Programming Erlang" (Pragmatic, 2007). ** motivation ------------------------------------------ MESSAGE-PASSING CONCURRENCY def: message passing is a programming style in which a program consists of that interact by Importance: ------------------------------------------ ... independent entities (agents) ... sending messages asynchronously Importance: ... service-oriented architecture multi-agent systems client-server systems (*key*) distributed systems (in general, if don't use shared memory) good for building highly reliable systems (as in Erlang) Q: What is asynchronous? Not waiting for a reply Q: What's the importance of message passing? - multi-agent systems have multiple software agents (actors) - natural for distributed systems reflects structure of system and its costs - lends itself to building highly reliable systems failures don't make other entities hang ** new concepts and capabilities *** spawn ------------------------------------------ FEATURE: SPAWNING A PROCESS spawn function: creates a new process Pid = spawn(Fun) Pid2 = spawn(mymodule,myfun,[Arg1,Arg2,...]) Pid3 = spawn(OtherMachine,Fun) % on OtherMachine Pid4 = spawn(OtherMachine,mymodule,myfun,[Arg1,Arg2,...]) Example: main() -> _Other = spawn(fun rest/0). rest() -> timer:sleep(200), io:format("message from process ~w~n", [self()]). ------------------------------------------ see spawndemo.erl The process runs in a separate address space, doesn't share scope except if passed a closure, so it has to communicate by message passing... A process can also be registered so it's known by an atom. See http://erlang.org/doc/reference_manual/processes.html#registered-processes *** send and receive ------------------------------------------ FEATURE: SENDING MESSAGES ! expression: sends to a named process Pid ! Message - sends Message to named Pid, and continues - all clients can always send - value is the value of Message ------------------------------------------ ... immediately (no waiting) (never fails, even if the Pid is invalid!) ------------------------------------------ FEATURE: RECEIVING MESSAGES receive expression: receives sent messages Example: loop() -> receive {P, doIt, X} -> P ! {self(), answer, X+2}, loop(); {P, halt} -> P ! ok end Syntax: ::= ... receive end ::= | ; ::= -> ::= | when is data with possible variable declarations ::= | after -> Semantics: - each process has a mailbox - server can read all messages - all patterns processed for each message, in order of oldest message to newest Fundamentally nondeterministic - receive resolves races in message sends ------------------------------------------ See sendreceive.erl and run the examples (demo1 and demo2, demo3) Scope of variables declared in a includes the guard and the rest of the . Q: What does it mean to be "named"? several clients can send to the Pid, all at same time Q: Do we still have referential transparency? no Note, Erlang's receive doesn't look for the first pattern in all messages before looking for the next pattern, instead it processes all the patterns against each message. Q: How, would you look through all messages of one type first? use a receive that ** semantics by example ------------------------------------------ SEND EXAMPLES (RACE CONDITIONS) -module(sendexamples). -export([main/0,server/0,client/2]). main() -> S = spawn(sendexamples,server,[]), spawn(sendexamples,client,[S,1]), spawn(sendexamples,client,[S,2]), spawn(sendexamples,client,[S,3]), spawn(sendexamples,client,[S,4]). server() -> receive({msg,N}) -> io:format("received ~b~n",[N]), server() end. dofor(I,F) -> if I > 0 -> F(), dofor(I-1,F); true -> done end. client(S,N) -> dofor(5, fun() -> W = rand:uniform(5), timer:sleep(W), S!{msg,N}, done end). ------------------------------------------ shows numbers in some random order Send puts the given value at the end of the targeted mailbox Q: How would you do this in Java? A process id is a new kind of object. Erlang uses the process id of a process as a (node-specific) name. Send is an operation on processes that mutates the stream it contains.