Let's say I have a process p1 and p2. When p1 ends, I also want p2 to end (p2 is waiting for an input from the user using io:get_line() when p1 ends). I can successfully end p1 by just letting the function end itself (no more code to execute), but how am I suppose to end p2 that is waiting for an input using p1?
These are the codes for the two processes:
chat1(2,Chat_Node,Name) ->
timer:sleep(100),
Message = io:get_line(io_lib:format("~s: ", [string:strip(Name,right,$\n)])),
case re:replace(Message, "\\s+", "", [global,{return,list}]) == [$b,$y,$e] of
true ->
Chat_Node ! bye;
false ->
Chat_Node ! {Name, Message},
chat1(2, Chat_Node, Name)
end.
chat2(2,Chat_Node,Name) ->
timer:sleep(100),
Message = io:get_line(io_lib:format("~s: ", [string:strip(Name,right,$\n)])),
case re:replace(Message, "\\s+", "", [global,{return,list}]) == [$b,$y,$e] of
true ->
{msg1, Chat_Node} ! bye;
false ->
{msg1, Chat_Node} ! {Name, Message},
chat2(2, Chat_Node, Name)
end.
After receiving an input from the user, the message is sent to the processes msg1 and msg2(Chat_Node). If the message is "bye", the process that has "bye" will end.
the process P1 can monitor the process P2 using the function: MonitorRef = erlang:monitor(process, P2)
Doing so, it will receive the message {'DOWN', MonitorRef, process, P2, Reason} when P2 will terminate and then perform the appropriate actions before finishing.
Note: a link wouldn't work if P2 ends normally (no more code to execute). It could work if P2 exits with another reason than normal
Edit
A small example in the shell (need to adapt in a module)
1> F = fun() -> io:format("Hello~n"),timer:sleep(2000) end.
#Fun<erl_eval.20.52032458>
2> G = fun() -> P2 = spawn(F),
2> MonitorRef = erlang:monitor(process,P2),
2> io:format("P1 waiting for P2 end~n"),
2> receive
2> {'DOWN', MonitorRef, process, P2, Reason} -> io:format("P2 finished with reason ~p~n",[Reason])
2> end,
2> io:format("P1 got message from P2~n")
2> end.
#Fun<erl_eval.20.52032458>
3> spawn(G).
P1 waiting for P2 end
Hello
<0.73.0>
P2 finished with reason normal
P1 got message from P2
4>
Edit 2
in this new example P2 get a float and transmit it to P1. if the input is a float, P2 exits with reason normal after sending the message {ok,Value} to P1 which in turn returns only Value. If the conversion from string to float fails, P2 exits with an error message which is catch by the second clause in the receive block. P1 recall itself (silly error management, just for illustration :o)
1> F = fun(From) ->
1> String = io:get_line("enter a float : "),
1> Float = list_to_float(string:strip(String,both,$\n)),
1> From ! {ok,Float}
1> end.
#Fun<erl_eval.20.52032458>
2> G = fun G() ->
2> P1 = self(),
2> P2 = spawn(fun() -> F(P1) end),
2> MonitorRef = erlang:monitor(process,P2),
2> receive
2> {ok,Float} -> Float;
2> {'DOWN', MonitorRef, process, P2, Reason} ->
2> io:format("this is not a float!"),
2> G()
2> end
2> end.
#Fun<erl_eval.20.52032458>
3> G().
enter a float : 5.2
5.2
4> G().
enter a float : hello
this is not a float!
=ERROR REPORT==== 3-Oct-2016::15:57:03 ===
Error in process <0.66.0> with exit value:
{badarg,[{erlang,list_to_float,["hello"],[]},
{erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,674}]},
{erl_eval,expr,5,[{file,"erl_eval.erl"},{line,438}]},
{erl_eval,exprs,5,[{file,"erl_eval.erl"},{line,122}]}]}
enter a float : 5.2
5.2
5>
Related
How do I implement a simultaneous passing from all values in a List A, to a List of Processes B? Both List A & B are of equal size. Let's say A = [1,2,3] and B = [<0.42.0>,<0.43.0>,<0.44.0>]. I want to pass the value 1 to process <0.42.0> and so on in parallel execution.
Here is what I came up so far:
pass_values([P|ValueListA], [H|ProcessListB]) ->
H ! {foo, P},
pass_values(ValueListA, ProcessListB).
What you are looking for is a scatter utility that takes an array of elements and distributes the elements to an array of processes.
-module(lab).
-compile(export_all).
go() ->
ProcessList =
lists:map(fun(_) ->
spawn(?MODULE, echo, [])
end,
lists:seq(1, 6)),
DataList = ["E", "r", "l", "a", "n", "g"],
scatter(DataList, ProcessList).
scatter(DataList, ProcessList) ->
lists:foreach(fun({Data, Process}) ->
Process ! Data
end,
lists:zip(DataList, ProcessList)).
echo() ->
receive
Msg ->
io:format("~p echos ~p~n", [self(), Msg]),
echo()
end.
Give it a try:
1> c(lab).
{ok,lab}
2> lab:go().
<0.40.0> echos "E"
<0.41.0> echos "r"
<0.42.0> echos "l"
<0.43.0> echos "a"
<0.44.0> echos "n"
<0.45.0> echos "g"
ok
I have a simple car process implemented in Erlang:
-module(cars).
-compile(export_all).
-record(state, {count=1}).
make_car() ->
spawn_link(fun() -> car_proc(#state{}) end).
car_proc(S) ->
receive
{idle, X} ->
io:format("idling for ~p second(s)~n", [X]),
timer:sleep(X*1000);
{move, {X,Y}} ->
io:format("move; x=~p, y=~p~n", [X,Y]);
{stop, Reason} ->
X = S#state.count,
io:format("stopped with count ~p because ~p~n", [X+1, Reason])
end,
X = S#state.count,
car_proc(S#state{count=X+1}).
I can make it idle, but if I call idle twice in a row, it breaks:
59> C = cars:make_car().
<0.207.0>
60> C!{idle,1}.
idling for 1 second(s)
{idle,1}
61> C!{idle,1}.
idling for 1 second(s)
{idle,1}
62>
=ERROR REPORT==== 9-Apr-2013::00:00:00 ===
Error in process <0.207.0> with exit value: {{badmatch,2},[{cars,car_proc,1,[{file,"cars.erl"},{line,20}]}]}
** exception error: no match of right hand side value 2
in function cars:car_proc/1 (cars.erl, line 20)
Why?
The error occurs on line 20, which is
X = S#state.count
It occurs because the pattern matching fails. The variable 'X' is already defined in this line and it's value is 1, because it has been determined in receive block:
receive
{idle, X} ->
In Erlang value of variable can be defined only one time. When you send message {idle, 1} first time X becomes 1 and default value of S#state.count is 1. So in that case 'X' matches S#state.count. When you send {idle, 1} second time X is 1 and S#state.count is 2 (i.e. X and S#state.count are not equal). So you get error in pattern matching. You can use another variable to avoid the problem. Change two last lines
X = S#state.count,
car_proc(S#state{count=X+1}).
to
Count = S#state.count,
car_proc(S#state{count=Count+1}).
and be happy!
Is there an equivalent expression for the increment/decrement operator e.g. counter++?
I also wonder how to properly do this?
-module(whileloop).
-export([call/0, while_loop/2]).
call() ->
while_loop(10,0).
while_loop(Var,Counter) ->
case Var =:= Counter of
false ->
Counter += 1,
whileloop(Var);
end.
edit:
-module(whileloop).
-export([call/0, while_loop/2]).
call() ->
while_loop(10,0).
while_loop(Var, Counter) ->
case Var =:= Counter of
false ->
while_loop(Var,Counter + 1)
end.
The meaning of C += 1 is to modify the value of C. It is a non sense in Erlang since it can only give the following result:
1> C = C+1.
* 1: variable 'C' is unbound
C = 1.
1
3> C = C+1.
** exception error: no match of right hand side value 2
Keep in mind that "A = B" does not mean assigns the value of B to A, but "pattern match" A against B,
if A is unbound then it will bind to A the value of B;
if A =:= B nothing is done, the process continue;
if A =/= B then the process crashes.
So yes, if you want to have a counter, or any information that change, you must use a state variable which is passed as argument of a recursive loop. From this point of view, your last code is correct, but lets follow what happens when you call "call()" in the shell.
first it calls, in the same process - the shell - the function while_loop(10,0).
10 is not equal to 0 so it calls immediately while_loop(10,1).
10 is not equal to 1 so it calls immediately while_loop(10,2).
and so on until it calls while_loop(10,10). Now 10 =:= 10 is true, and this result does not match any clause of the case, so you get an error and the process crash.
As your code does not contain any message receive and simply loop an loop until it crashes, thhe wole process takes only a few micro seconds, so it looks like it fails immediately.
Depending on what you expect, you can imagine several types of counter, here are 2 examples:
-module(counter).
-compile(export_all).
% one counter that help you to count some events
% interface
start_c1(End) when is_integer(End) ->
spawn(?MODULE,counter1,[End]).
start_link_c1(End) when is_integer(End) ->
spawn_link(?MODULE,counter1,[End]).
inc_c1(Pid) when is_pid(Pid) ->
Ref = make_ref(),
Pid ! {inc,self(),Ref},
receive
{Ref,done} -> done;
{Ref,V} -> V
after 1000 ->
{error,no_response}
end.
value_c1(Pid) when is_pid(Pid) ->
Ref = make_ref(),
Pid ! {get_value,self(),Ref},
receive
{Ref,V} -> V
after 1000 ->
{error,no_response}
end.
stop_c1(Pid) when is_pid(Pid) ->
Pid ! stop.
% the counter
counter1(End) -> counter1_loop(End,0).
counter1_loop(End,V) ->
receive
{inc,Pid,Ref} when V =/= done ->
NewV = case V+1 of
End -> done;
Nv -> Nv
end,
Pid ! {Ref,NewV},
counter1_loop(End,NewV);
{inc,Pid,Ref} ->
Pid ! {Ref,done},
counter1_loop(End,done);
{get_value,Pid,Ref} ->
Pid ! {Ref,V},
counter1_loop(End,V);
stop ->
ok
end.
% One kind of timeout that execute something after a while -
% note it exists a similar one in the library
start_after(T,M,F,A) when is_integer(T), is_list(A) ->
Ref = make_ref(),
{Ref,spawn(?MODULE,after_receive,[T,M,F,A,self(),Ref])}.
cancel_after(P) when is_pid(P) ->
P ! cancel.
% the counter
after_receive(T,M,F,A,Pid,Ref) ->
receive
{cancel,Ref} -> Pid ! {after_receive,Ref,cancelled}
after T ->
Pid ! {after_receive,Ref,done},
apply(M,F,A)
end.
and here how to use them:
1> c("../src/counter").
{ok,counter}
2> {Ref,P} = counter:start_after(5000,io,format,["This is the end!" ]).
{#Ref<0.0.0.29>,<0.33.0>}
This is the end!3>
3> {Refa,Pa} = counter:start_after(50000,io,format,["This is the end!" ]).
{#Ref<0.0.0.34>,<0.35.0>}
4> Pa ! {cancel,Refa}.
{cancel,#Ref<0.0.0.34>}
5> flush().
Shell got {after_receive,#Ref<0.0.0.29>,done}
Shell got {after_receive,#Ref<0.0.0.34>,cancelled}
ok
6> P1 = counter:start_c1(5).
<0.52.0>
7> counter:inc_c1(P1).
1
8> counter:inc_c1(P).
{error,no_response}
9> counter:inc_c1(P1).
2
10> counter:inc_c1(P1).
3
11> counter:value_c1(P1).
3
12> counter:inc_c1(P1).
4
13> counter:inc_c1(P1).
done
14> counter:value_c1(P1).
done
15> counter:inc_c1(P1).
done
16> counter:stop_c1(P1).
stop
17> counter:inc_c1(P1).
{error,no_response}
18>
Just recursively call while_loop with the Counter argument incremented by one:
while_loop(Var, Counter + 1)
Your edited version doesn't have a clause when Var =:= Counter and thus crashes. And you'd better use pattern matching in function clauses.
-module(whileloop).
-export([call/0, while_loop/2]).
call() ->
while_loop(10,0).
while_loop(Var, Var) ->
ok;
while_loop(Var, Counter) ->
while_loop(Var, Counter + 1).
And of course you'd need to do something inside the loop. You can use lambdas for that:
-module(whileloop).
-export([call/0, while_loop/3]).
call() ->
while_loop(10, 0, fun(Counter) -> io:format("Counter: ~p~n", [Counter]) end).
while_loop(Var, Var, _) ->
ok;
while_loop(Var, Counter, Fun) ->
Fun(Counter),
while_loop(Var, Counter + 1, Fun).
I am new to Erlang, I need to spawn two process running add function, then add the
two numbers.
assigned value of Process one and two is showing the process id, I need catch the value.
How can I read the return value of add(N) function in my calc function?
-module(myerl).
-export([calc/1,add/1]).
add(N) ->
N + 5.
calc(L)
pone = spawn( fun() -> add(A) end),
ptwo = spawn( fun() -> add(B) end),
Result = Pone + Ptwo,
io:format("result ~p~n", [Result]).
You need to use message passing. You must send a message back to the calling process with the result. The spawn function returns a PID (process identifier) to the newly spawned process, not the result of its execution.
This example should do what you're expecting:
calc(A, B) ->
Self = self(), % The spawned funs need a Pid to send to, use a closure
POne = spawn(fun() -> Self ! {self(), add(A)} end),
PTwo = spawn(fun() -> Self ! {self(), add(B)} end),
wait_for_response(POne, PTwo, 0).
wait_for_response(undefined, undefined, Sum) ->
Sum;
wait_for_response(POne, PTwo, Sum) ->
receive
{POne, V} -> wait_for_response(undefined, PTwo, Sum + V);
{PTwo, V} -> wait_for_response(POne, undefined, Sum + V)
end.
#Soup d'Campbells' explanation is good. I instinctively did something slightly different which, in a toy way, anticipates some bad behavior with the child processes. Also, I allow the input to be a list of numbers, not just 2.
-module(myerl).
-export([calc/1, add/1]).
calc(NumList) when is_list(NumList)->
Parent = self(),
_Pids = [spawn(fun()-> Parent ! add(ANum) end) || ANum <- NumList],
collect(length(NumList), 0);
calc(_) ->
{error, badarg}.
collect(0, Sum) ->
Sum;
collect(Cnt, Sum) ->
receive
N when is_number(N) ->
collect(Cnt-1, Sum + N);
_Bad -> % returned something that isnt a number
collect(Cnt-1, Sum)
after 1000 -> % died or is too slow
collect(Cnt-1, Sum)
end.
add(N) ->
N + 5.
startTrains() ->
TotalDist = 100,
Trains = [trainA,trainB ],
PID = spawn(fun() ->
train(1,length(Trains)) end),
[ PID ! {self(),TrainData,TotalDist} || TrainData <- Trains],
receive
{_From, Mesg} ->
error_logger:info_msg("~n Mesg ~p ~n",[Mesg])
after 10500 ->
refresh
end.
so, I created Two Processes named trainA, trainB. I want to increment these process by 5 till it gets 100. I made different processes to make each of the train (process) increments its position parallely. But I was surprised to get the output sequentially i.e process trainA ends then process trainB starts. But I want to increment themselves at simultaneously.
I want to run processes like this
trainA 10 trainB 0
trainA 15 trainB 5
....
trainA 100 trainB 100
but I m getting
trainA 0
....
trainA 90
trainA 95
trainA 100
trainA ends
trainB 0
trainB 5
trainB 10
.....
trainB 100
How to make the processes run parallel/simultaneously? Hope you get my Q's. Please help me.
You spawn only one process initialized by function train/2. Your presented code is incomplete so I can only guess but I think your code is wrong because you have only one train process. For inspiration:
-module(trains).
-export([startTrains/0]).
startTrains() ->
TotalDist = 100,
Names = [trainA,trainB ],
Self = self(),
Trains = [spawn_link(fun() ->
train(Name, Self) end) || Name <- Names],
[ Train ! {start, Self, 0, TotalDist} || Train <- Trains],
ok = collectResults(Names).
collectResults([]) -> ok;
collectResults(Trains) ->
receive
{stop, Name, Pos, Length} ->
io:format("~p stops at ~p (~p)~n", [Name, Pos, Length]),
collectResults(Trains -- [Name]);
Msg ->
io:format("Supervisor received unexpected message ~p~n", [Msg]),
collectResults(Trains)
after 10500 -> timeout
end.
train(Name, Sup) ->
receive
{start, Sup, Pos, Length} -> run_train(Name, Sup, Pos, Length);
Msg ->
io:format("~p received unexpected message ~p~n", [Name, Msg]),
train(Name, Sup)
end.
run_train(Name, Sup, Pos, Length)
when Pos < Length ->
receive after 500 ->
NewPos = Pos + 5,
io:format("~p ~p~n", [Name, Pos]),
run_train(Name, Sup, NewPos, Length)
end;
run_train(Name, Sup, Pos, Length) ->
Sup ! {stop, Name, Pos, Length}.
But if I would think it seriously I should look to gen_fsm and OTP principles. But in your current stage keep play with erlang primitives to take better feeling first.