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.
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.
Related
I have the following code:
-module(a).
-compile(export_all).
say(2,0) ->
[1,2];
say(A,B) ->
say(A-1,B-1).
loop(0) ->
io:format("");
loop(Times) ->
L = spawn(a, say, [4,2]),
io:fwrite( "L is ~w ~n", [L] ),
loop(Times-1).
run() ->
loop(4).
I want to have the list [1,2] in L each time function 'say' completes. However, since the pid of the process is returned instead of the list from the function say due to use of spawn, I am getting the following output:
L is <0.113.0>
L is <0.114.0>
L is <0.115.0>
L is <0.116.0>
What I desire is
L is [1,2]
L is [1,2]
L is [1,2]
L is [1,2]
How can I achieve this?
To pass information between processes, you use ! to send a message to another process's mailbox, and you use a receive clause to extract a message from a process mailbox. Here is an example:
-module(a).
-compile(export_all).
%% Worker process:
say(From, 2, 0) ->
From ! {self(), [1,2]};
say(From, A, B) ->
say(From, A-1, B-1).
%% Main process:
loop(0) ->
ok;
loop(Times) ->
Pid = spawn(a, say, [self(), 4, 2]),
receive %%waits here for result before spawning another process--no concurrency
{Pid, Result} ->
io:fwrite( "L is ~w ~n", [Result] )
end,
loop(Times-1).
%% Test:
run() ->
loop(4).
In the shell:
7> c(a).
a.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,a}
8> a:run().
L is [1,2]
L is [1,2]
L is [1,2]
L is [1,2]
ok
9>
Or, you can spawn all the processes, then read the results as they come in:
-module(a).
-compile(export_all).
%% Worker process:
say(From, 2, 0) ->
From ! [1,2];
say(From, A, B) ->
say(From, A-1, B-1).
%% Main process:
loop(N) ->
loop(N, N).
loop(0, Times) ->
display_results(Times);
loop(N, Times) ->
spawn(a, say, [self(), 4, 2]),
loop(N-1, Times).
display_results(0) ->
ok;
display_results(Times) ->
receive
Result ->
io:format("L is ~w~n", [Result])
end,
display_results(Times-1).
%% Test:
run() ->
loop(4).
To ensure that you only receive messages from the processes that you spawned, you can do this:
-module(a).
-compile(export_all).
%% Worker process:
say(From, 2, 0) ->
From ! {self(), [1,2]};
say(From, A, B) ->
say(From, A-1, B-1).
%% Main process:
loop(Times) ->
loop(Times, _Pids=[]).
loop(0, Pids) ->
display_results(Pids);
loop(Times, Pids) ->
Pid = spawn(a, say, [self(), 4, 2]),
loop(Times-1, [Pid|Pids]).
display_results([]) ->
ok;
display_results([Pid|Pids]) ->
receive
{Pid, Result} ->
io:format("L is ~w~n", [Result])
end,
display_results(Pids).
%% Test:
run() ->
loop(4).
There are some risks when using a receive like that: if a worker process crashes before it sends the message to your main process, then your main process will be stuck indefinitely in the receive while waiting for a message to arrive from the crashed process. One solution: use a timeout in the receive. Another: use spawn_monitor().
You need to use messages (or signals) for that, as the code is running in a separate process.
I like to use spawn_monitor in that case:
1> {Pid, MonitorReference} = spawn_monitor(fun() -> timer:sleep(10000), exit({ok, [1,2]}) end),
1> receive {'DOWN', MonitorReference, process, Pid, {ok, Result}} -> Result end.
Keep in mind that you can receive for several messages at the same time or you can just receive them in order (leaving the out of order ones in the mailbox). So you can spawn several threads and wait for all of them to be finished, gathering the results:
work(Workload) ->
JobReference = make_ref(),
PidReferences = [spawn_monitor(fun() -> exit({JobReference, do_stuff(WorkSlice)}) end) || WorkSlice <- Workload],
[receive
{'DOWN', Reference, process, Pid, {JobReference, Result}} -> Result;
{'DOWN', Reference, process, Pid, Result} -> {error, Result}
end || {Pid, Reference} <- PidReferences].
What I understand is that -export() make it possible to expose some, but not all, functions in a module definition. Inside the module definition, all functions are available, however.
I have a module that looks like this
-module(supervisor_test).
-export([start_listening/0, stop_listening/0, send_to_listener/1]).
listener() ->
receive
{Pid, Ref, x} ->
Pid ! {Ref, o};
{Pid, Ref, o} ->
Pid ! {Ref, x}
end.
supervisor() ->
process_flag(trap_exit, true),
Pid = spawn_link(?MODULE, listener, []),
register(reg_listener, Pid),
receive
{'EXIT', Pid, normal} -> % received when listener() finishes executing
ok;
{'EXIT', Pid, shutdown} -> % received when stop_listening() is called
ok;
{'EXIT', Pid, _} ->
supervisor()
end.
start_listening() ->
spawn(?MODULE, supervisor, []).
stop_listening() ->
Pid = whereis(reg_listener),
exit(Pid, shutdown).
send_to_listener(Value) ->
Ref = make_ref(),
reg_listener ! {self(), Ref, Value},
receive
{Ref, Reply} -> Reply
after 5000 ->
timeout
end.
Whenever I compile and call supvervisor_test:start_listening(), I get the following error
=ERROR REPORT==== ... ===
Error in process ... with exit value:
{undef,[{supervisor_test,supervisor,[],[]}]}
It goes away if I export_all and expose everything.
I tried compiling
-module(test).
-export([f1/0]).
f1() ->
f2().
f2() ->
io:format("I am here!~n").
and calling test:f1() and it works fine.
In start_listener() you're calling the MFA version of spawn(). This will use apply() and the apply docs state: "The applied function must be exported from Module."
If I log a function:
Debug.log "List.foldl" (toString List.foldl)
<function> : a -> a
I get its function signature. How do I get the body of the function?
Debug.log takes two arguments: string and any variable. Both of them will be printed out and first paramenter should be used as a simple description what you are sending to logs.
In your case it could be:
Debug.log "List.foldl func" <| List.foldl
<function>
: (a -> b -> b) -> b -> List a -> b
I'm making an event calender as a task for school and I'm new to this.
The problem is that when I do a delay in the receive part of my loop, my table vanishes.
I'm looking on the internet and in my code for errors for 2 days now.
Event is a tuple => {{Time (tuple like now(), make_ref()}, NotifyPid, Load}
getTime gives back an integer normally
-module(calender).
-export([start/0, start_new/0, post/1, postincr/1, gettime/0]).
-export ([kalender/0, getTime/1, increment/1, makeTime/1]). % internal use only
%% #doc Starts the program
start() ->
case whereis('event manager') =:= undefined of
true ->
register('event manager', spawn(calender, kalender, [])),
{ok, 'event manager'};
false ->
{event_not_made}
end.
%% #doc Starts a new program even program already exist but kills it first
start_new() ->
case whereis('event manager') =:= undefined orelse unregister('event manager') of
true ->
ets:delete(calend),
register('event manager', spawn(calender, kalender, [])),
{ok, 'event manager'};
false ->
{ok, event_not_made}
end.
% Puts Events into sorted table
% Time is an integer value in milliseconds
post(Event) ->
'event manager'!{post, Event},
{ok, gettime()}.
%% #doc Puts Events into sorted table
%% Increment is an integer value which will be added to the present time
%% The increment value of time is in milliseconds
%% #end
postincr(Event) ->
'event manager'!{postincr, Event},
{ok, gettime()}.
%% #doc Gives the difference in time between present and time at start
gettime() ->
'event manager'!{gettime, self()},
receive
T -> T
end.
%% #private Calculates the difference of time between the present time and Event time
getTime(Time) ->
NowTime = now(),
timer:now_diff(Time, NowTime)div 1000.
%% #private Adds the incremental time of postincr to the present time
increment(Incr) ->
{X, Y, Z} = now(),
X1 = X * 1000000000000,
Y1 = Y * 1000000,
Incr1 = X1 + Y1 + Z + (Incr * 1000),
makeTime(Incr1).
%% #private Changes integer to tuple of 3 values
makeTime(Time) ->
X = Time div 1000000000000,
Y = (Time rem 1000000000000) div 1000000,
Z = Time rem 1000000,
{X, Y, Z}.
%% #private Makes the sorted table, starts the loop
kalender() ->
Cal = {ets:new(calend, [ordered_set, named_table, {keypos, 1}, public]), now()},
loop(Cal).
%% #private Loops through the table and checks for received messages
loop(Cal) ->
io:format("Loop start ~n"),
{Calen, TimeAtStart} = Cal,
io:format("Before case ~n"),
case ets:first(Calen) of
'$end_of_table' ->
io:format("end of table ~n"),
{end_of_table};
{Time, Ref} ->
io:format("Before calculation event ~n"),
Ms = getTime(Time),
io:format("After getTime ~n"),
if
Ms =< 0 ->
io:format("Ms =< 0 ~n"),
[Event | _Rest] = ets:lookup(Calen, {Time, Ref}),
io:format("~p~n", [Event]),
{{_Time1, _Ref1}, NotifyPid, _Load} = Event,
io:format("~p~n", [NotifyPid]),
NotifyPid!Event,
io:format("After event send ~n"),
ets:delete(Calen, {Time, Ref}),
io:format("After Ms =< 0 ~n");
Ms > 0 ->
io:format("Event not done ~n"),
{event_not_yet_done}
end,
io:format("After calculation event ~n")
end,
I think that it goes wrong from here somewhere:
io:format("Before Delay ~n"),
% Gets the delay time
Delay = case ets:first(Calen) of
'$end_of_table' ->
io:format("Delay infinity ~n"),
infinity;
{DelayTime, _DelayRef} ->
io:format("~p~n", [DelayTime]), => the DelayTime has for example a value of {9283,823031,155000}
Dl = getTime(DelayTime),
case Dl > 0 of
true ->
Dl,
io:format("~p~n", [Dl]); => this io:format gives me on the screen a calculated value example: 7899995274337
false ->
0,
io:format("0 ~n")
end,
io:format("Delay time~n")
end,
io:format("Before receive ~n"),
receive
{post, PostEvent} ->
io:format("In post ~n"),
{PostTimeI, Np, Ld} = PostEvent,
PostRef = make_ref(),
PostTimeT = makeTime((PostTimeI * 1000)),
io:format("After making the tuples ~n"),
io:format("~p ~p ~p ~p ~p~n", [PostTimeI, PostRef, PostTimeT, Np, Ld]),
ets:insert(Calen, {{PostTimeT, PostRef}, Np, Ld}),
io:format("After insert post ~p~n", [whereis('event manager')]);
{postincr, PostIncrEvent} ->
{Incr, Np, Ld} = PostIncrEvent,
PostIncrRef = make_ref(),
PostIncrTime = increment(Incr),
ets:insert(Calen, {{PostIncrTime, PostIncrRef}, Np, Ld});
{gettime, From} ->
From!getTime(TimeAtStart)
after
Delay ->
io:format("Delaying ~n"),
{ok}
end,
io:format("After receive ~n"),
loop(Cal).
The problem is probably that your process spawned with your start/0 function crashes. When a process crashes, any ETS tables it owns are reaped. Try using spawn_monitor and then use the shell's flush() command to get hold of messages that comes in. It probably dies. Another way is to use the tooling in the proc_lib module and then use erl -boot start_sasl to get some rudimentary crash error reporting up and running for your process.
A "naked" spawn(...) is usually dangerous since if the spawned process crashes, you won't learn anything. At least use spawn_link or spawn_monitor.
I found my problem:
I was testing my code but I didn't had a Pid to test with, so I used whereis('event manager'). Instead I had to use self().
I am new at Erlang, and I have the following homework-problem to solve:
A "control" process has to offer a user function go(N,M) that
generates a lists L of M random integer numbers in {1,2,...,M},
sets up ring of N processes (so-called "workers") and sends a token
to the first worker. When worker k receives a token, it sends a
message {eat, self()} to control and sends the token to next worker.
When control receives a message {eat, Pid}, it withdraws the head H of the list
L and appends to a result list the tuple {H, Pid}. When list L is empty, control
sends a stop message to the ring that terminates the workers and prints the result
list.
Any help would be apreciated
Actually there were two approaches to solve this problem.
The first one is:
The control spawns all the workers in the ring and here is the solution:
-module(ring).
-export([start/3, create/4]).
start(M, N, Message) ->
create(undef, N, M, Message).
create(Parent, 0, M, Message) ->
Parent ! {created, self()},
evaluate(Parent, M, Message);
create(Parent, N, M, Message) ->
Child = spawn(?MODULE, create, [self(), N-1, M, Message]),
io:format("~w ~w created~n", [Child, N]),
evaluate(Parent, M, Message).
evaluate(undef, M, Message) ->
receive
{created, Last} ->
Last ! Message,
io:format("~w sent ~w to ~w~n", [self(), Message, Last]),
evaluate(Last, M-1, Message)
end;
evaluate(Parent, 0, _) ->
receive
Msg ->
io:format("~w received ~w~n", [self(), Msg]),
Parent ! stop,
io:format("~w sent ~w to ~w~n", [self(), stop, Parent])
end;
evaluate(Parent, M, Message) ->
receive
{created, Last} ->
Parent ! {created, Last},
evaluate(Parent, M, Message);
Message ->
io:format("~w received ~w~n", [self(), Message]),
Parent ! Message,
io:format("~w sent ~w to ~w~n", [self(), Message, Parent]),
evaluate(Parent, M-1, Message)
end.
And the second one is:control spawns only the first worker in the ring. Every new worker
in the ring, but the last one, spawns the next worker:
-module(ring).
-export([start/3, start_process/1, start_process/2]).
start(M, N, Message) ->
Pid = spawn(ring, start_process, [N]),
Pid ! {message, Message, M},
ok.
start_process(Count) ->
% This is the first spawned process - send its
% pid down the chain so the last process knows who its
% next pid is.
io:format("~p: Spawned ~p~n", [self(), Count]),
Pid = spawn(ring, start_process, [Count-1, self()]),
loop(Pid).
start_process(0, Last) ->
% This is the last process
io:format("~p: Linking to last ~p~n", [self(), Last]),
loop(Last);
start_process(Count, Last) ->
io:format("~p: Spawned ~p~n", [self(), Count]),
Pid = spawn(ring, start_process, [Count-1, Last]),
loop(Pid).
loop(NextPid) ->
receive
{message, _, 0} -> true;
{message, Msg, M} ->
io:format("~p (~p) ~p~n", [Msg, self(), M]),
NextPid ! {message, Msg, M-1},
loop(NextPid)
end.