Reputation: 5575
I modified the kitchen module from Learn you some Erlang using standard IO functions to see what gets printed out in the order of execution and I found something really strange. Basically I ran the following in the shell
3> Pid = spawn(kitchen, fridge2, [[baking_soda]]).
<0.41.0>
4> kitchen:store(Pid, water).
0
2
1
ok
ok
It seems to me the function store has a call to the function fridge2 before the receive clause in the store function right after 0 is printed out and then after 2 is printed the receive clause is executed and 1 is finally printed. The modified code is below. How is the fridge2 function called from store function? Is this because of parallel execution somehow? What does this line do {Pid, Msg} ->
in the store function? Is it a function call? and why is ok printed?
-module(kitchen).
-compile(export_all).
start(FoodList) ->
spawn(?MODULE, fridge2, [FoodList]).
store(Pid, Food) ->
Pid ! {self(), {store, Food}},
io:format("~p~n", [0]),
receive
{Pid, Msg} ->
io:format("~p~n", [1]),
io:format("~p~n", [Msg]),
Msg
end.
take(Pid, Food) ->
Pid ! {self(), {take, Food}},
receive
{Pid, Msg} -> Msg
end.
store2(Pid, Food) ->
Pid ! {self(), {store, Food}},
receive
{Pid, Msg} -> Msg
after 3000 ->
timeout
end.
take2(Pid, Food) ->
Pid ! {self(), {take, Food}},
receive
{Pid, Msg} -> Msg
after 3000 ->
timeout
end.
fridge1() ->
receive
{From, {store, _Food}} ->
From ! {self(), ok},
fridge1();
{From, {take, _Food}} ->
%% uh....
From ! {self(), not_found},
fridge1();
terminate ->
ok
end.
fridge2(FoodList) ->
receive
{From, {store, Food}} ->
From ! {self(), ok},
io:format("~p~n", [2]),
fridge2([Food|FoodList]);
{From, {take, Food}} ->
case lists:member(Food, FoodList) of
true ->
io:format("~p~n", [3]),
From ! {self(), {ok, Food}},
fridge2(lists:delete(Food, FoodList));
false ->
io:format("~p~n", [4]),
From ! {self(), not_found},
fridge2(FoodList)
end;
terminate ->
ok
end.
Upvotes: 1
Views: 220
Reputation: 2723
similar to case statements, receive uses pattern matching to determine what clause to execute. {Pid, Msg}
is a clause that will match any 2-tuple.
let's walk through you the execution of your code --
Pid = spawn(kitchen, fridge2, [[baking_soda]]).
this spawns a new process that executes the kitchen:fridge2/1
function. that function blocks until it receives a message that is either a 2-tuple of the form {From, {[store|take], Food}}
or the atom 'terminate'.
kitchen:store(Pid, water).
meanwhile, you call the above function from the shell. It sends the message {self(), {store, Food}}
to that new process, prints "0" and then waits to receive a message that is a 2-tuple.
the other process has now received a message that satisties its receive. It sends the message {self(), ok}
back to the process who sent the message, prints "2", recursively calls itself and again waits to receive a message.
the shell process has now received a message and continues execution. it prints "1" and then prints the second element of the tuple it received ("ok"). finally it returns 'ok' to the shell.
the shell prints the result ("ok") and displays a prompt.
the second process is still waiting to receive a message.
Upvotes: 1