Erlang (programming language)/Tutorials/Processes
The metadata subpage is missing. You can start it via filling in this form or by following the instructions that come up after clicking on the [show] link to the right. | |||
---|---|---|---|
|
Erlang Processes and Messages
Processes are easy to create and control in erlang. The program chain_hello.erl builds a chain of processes as long as you like. Each process creates one process then sends a message to it. The program creates a chain of N processes which each print out hello world! N. Processes send messages and receive messages from one another. Messages are read with pattern matching. The messages are matched in a fifo(first in, first out) way.
Note 1: The order of the final output depends on process scheduling.
Note 2: Time flows downward(in each vertical line for each process, see note 1).
This is a minimal UML sequence diagram showing the processes and messages for the execution of:
chain_hello:start(1). UML sequence notation: Processes start in boxes. Dotted lines are life lines. Processes time lines end in X's. Note: Some of the details of have been left out for tutorial purposes. The diagram has English mixed with code. Local notation: Command line output is in quotes. Messages are in curly braces.
+——————————+ | start(1) | +——————————+ ¦ +———————————+ spawns ———————> | listen(1) | ¦ +———————————+ ¦ ¦ +———————————+ ¦ spawns ————————————————> | listen(0) | ¦ ¦ +———————————+ ¦ ¦ ¦ sends —> {speak} —> prints —> "hello world 1" ¦ ¦ ¦ ¦ ¦ sends ——> {speak} ———————> prints ———> "hello world 0" ¦ ¦ ¦ X X X
Program listing for: chain_hello.erl
-module(chain_hello). -compile(export_all). % start(N)-> % startup Pid1 = spawn(chain_hello, listen, [N]), Pid1 ! speak, io:format("done \n"). % listen(0)-> % base case receive speak -> io:format("hello world!~w\n", [0]) end; listen(N)-> % recursive case Pid2= spawn(chain_hello, listen, [N-1]), Pid2! speak, receive speak-> io:format("hello world!~w\n", [N]) end.
% ---- sample output for chain_hello:start(1) --- % % % 14> chain_hello:start(1). % done % okhello world!1 % hello world!0 % % ---- sample output for chain_hello:start(4) --- % % % 14> chain_hello:start(4). % done % hello world!4 % hello world!3 % hello world!2 % okhello world!1 % hello world!0
Intermediate message passing
Now, suppose we have some commands in the form of a message. We wish to send this command message to a large set of processes. We might like answers from those processes that are able to respond. If some crash because of the message then they should be restarted.
% ===========================================================================
-module(freeze_clone). -compile(export_all).
% The purpose of freeze_clone is to non-destructively test a process with a % message. Each process is a state machine. % If the process receives any unknown message then it should self destruct, % (Because we are following the rule: to fail early and often). % Each msg_testable process requires the following message handlers: % {freeze, clone, get_value, set_value, exit}. % % Steps to test a message on a process: % 0) setup: spawn a process to listen to messages % 1) freeze process in question so it is safe to clone % 2) we clone the process % 3) send the clone a test message % 4) unfreeze the clone % 5) see if clone lived after the message, % if the clone is happy/alive then the message should be safe % 6) kill clone if clone is alive % 7) send message to original or % pick another safer message if msg failed on clone % 8) unfreeze original % 9) request resulting value from original % % test(Pid, msg) loopy() % | | % | | % o - freeze ---> o % | | % o - clone ----> o == spawn ==> loopy() clone % | | | % o - msg -------------------------------------> o % | | | % o - get_value -------------------------------> o % | | | % o <--- value --------------------------------- o % | | | % o ------------------ [if clone is alive] halt --> x % | | % o - unfreeze --> o % | | % \|/ % return msg is % safe or unsafe: % {true or false} % -------------------------------------------------------------------- % Sample output: % [{msg, keep_on_trucking, is_safe, false}, % {msg, bump, is_safe, true}] % --------------------------------------------------------------------
start() -> Pid = spawn(freeze_clone, loopy, [{1, false}] ), % process loopy Msg_1 = keep_on_trucking, % message to test on process loopy Safe_1 = test(Pid, Msg_1), % ------------------------ Msg_2 = bump, Safe_2 = test(Pid, Msg_2), io:format("\n"), [ {msg, Msg_1, is_safe, Safe_1}, {msg, Msg_2, is_safe, Safe_2} ]. test(Pid, Msg) -> Pid ! freeze, ClonePid = rpc(Pid, clone), ClonePid ! unfreeze, Before = rpc(ClonePid, get_value), % send test msg to clone ClonePid ! Msg, Result = rpc(ClonePid, get_value), if Result == no_one_can_answer -> Safe = false; true -> Safe = true end, if Safe == true -> ClonePid ! exit, Pid ! unfreeze, Pid ! Msg, After = rpc(Pid, get_value); true -> Pid ! unfreeze, After = no_value end, Results = {'message_tried:', Msg, 'message_transition_is_safe:', Safe, 'state_machine_name:', loopy, 'value_before:', Before, 'value_after:', After}, io:format("\n ~w \n",[Results]), Safe. loopy(State) -> {Value, Freeze} = State, if Freeze == false -> receive {From, get_value} -> From ! Value; {set_value, NValue} -> loopy({NValue, Freeze}); bump -> loopy({Value+1, Freeze}); freeze -> loopy({Value, true}); exit -> exit(normal); {Error, Error_Msg} -> io:format("error: ~w \n",[{Error, Error_Msg}]); _Any -> exit(normal) end; Freeze == true -> receive unfreeze -> loopy({Value,false}); {From, clone} -> Pid2 = spawn( freeze_clone, loopy, [{Value, Freeze}]), From ! Pid2 end; true -> ok end, loopy(State). rpc(To, Msg) -> To ! {self(), Msg}, receive Answer -> Answer after 1000 -> Answer = no_one_can_answer end, Answer. % =============================================================== %6> c(freeze_clone). %{ok,freeze_clone} %7> freeze_clone:start(). %{'message_tried:',keep_on_trucking,'message_transition_is_safe:', false,'state_machine_name:',loopy,'value_before:',1,'value_after:',no_value}
%{'message_tried:',bump,'message_transition_is_safe:', true,'state_machine_name:',loopy,'value_before:',1,'value_after:',2}
%[{msg,keep_on_trucking,is_safe,false}, %{msg,bump,is_safe,true}]