Reputation: 13
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.
Upvotes: 0
Views: 350
Reputation: 14042
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>
Upvotes: 2