From the example given here, Erlang and process_flag(trap_exit, true)
-module(play).
-compile(export_all).
start() ->
process_flag(trap_exit, true),
spawn_link(?MODULE, inverse, [***0***]),
loop().
loop() ->
receive
Msg -> io:format("~p~n", [Msg])
end,
loop().
inverse(N) -> 1/N.
If I run it as,
A = spawn(play, start, []).
The spawned process <0.40.0> dies as it is suppose to but the main process (A <0.39.0>) which spawned it doesn't die.
{'EXIT',<0.40.0>,{badarith,[{play,inverse,1,[{file,"play.erl"},{line,15}]}]}}
<0.39.0>
i().
....
....
<0.39.0> play:start/0 233 19 0
play:loop/0 1
A does get an exit signal (not an exit message since A is not trapping exit) then why doesn't it exit?
The reason for this is that you set a trap_exit flag to true which means this process will get {'EXIT', FromPid, Reason} message instead of being killed. Just remove process_flag(trap_exit, true) or in case of receiving this type of message, kill it.
You can read about it here.
Related
Simple code:
-module(on_exit).
-export([on_exit/2, test/0]).
on_exit(Pid, Fun) ->
spawn(fun() ->
Ref = erlang:monitor(process, Pid),
receive
{'DOWN', Ref, process, Pid, Why} ->
Fun(Why)
end
end).
test() ->
Fun1 = fun() -> receive Msg -> list_to_atom(Msg) end end,
Pid1 = spawn(Fun1),
Fun2 = fun(Why) -> io:format("~w died with error: ~w~n", [Pid1, Why]) end,
_Pid2 = spawn(on_exit, on_exit, [Pid1, Fun2]),
Pid1 ! hello.
In the shell:
1> c(on_exit).
{ok,on_exit}
2> on_exit:test().
<0.39.0> died with error: noproc
hello
3>
=ERROR REPORT==== 9-Apr-2017::05:16:54 ===
Error in process <0.39.0> with exit value: {badarg,[{erlang,list_to_atom,[hello],[]},{on_exit,'-test/0-fun-0-',0,[{file,"on_exit.erl"},{line,14}]}]}
Expected Output:
5> Pid1 ! hello.
<0.35.0> died with error: {badarg,[{erlang,list_to_atom,[hello],[]}]}
hello
6>
=ERROR REPORT==== 9-Apr-2017::05:15:47 ===
Error in process <0.35.0> with exit value: {badarg,[{erlang,list_to_atom,[hello],[]}]}
In fact, the expected output is what I see if I take each line in test() and paste it into the shell. Why do I get the noproc (no process) error when I run the same lines inside a function?
From the docs:
12.8 Monitors
An alternative to links are monitors. A process Pid1 can create a
monitor for Pid2 by calling the BIF erlang:monitor(process, Pid2). The
function returns a reference Ref.
If Pid2 terminates with exit reason Reason, a 'DOWN' message is sent
to Pid1:
{'DOWN', Ref, process, Pid2, Reason}
If Pid2 does not exist, the 'DOWN' message is sent immediately with
Reason set to noproc.
Your code contains a race condition -- spawn is asynchronous and might return before the process is spawned, and you might end up sending and crashing Pid1 before on_exit:on_exit/2 starts monitoring it, which causes the erlang:monitor/2 call to immediately send a noproc message to the caller:
1> Pid = spawn(fun() -> ok end).
<0.59.0>
2> erlang:monitor(process, Pid).
#Ref<0.0.1.106>
3> flush().
Shell got {'DOWN',#Ref<0.0.1.106>,process,<0.59.0>,noproc}
ok
The code works fine in the shell probably because the Erlang VM executes some things slowly in the shell than when the code is compiled, but this behavior is not guaranteed. This is a classic race condition.
Erlang has a solution for this: erlang:spawn_monitor/{1,3}. This function is guaranteed to attach the monitor as soon as the function is spawned. You'll have to re-arrange your code a bit to use it instead of spawn/3 + erlang:monitor/1.
Is this how you avoid a race condition?
-module(b).
-export([my_spawn/1]).
my_spawn(Func) ->
Pid = spawn(listener()),
Pid ! {self(), spawn, Func},
receive
{From, Desired_Pid} -> Desired_Pid
end.
listener() ->
receive
{From, spawn, Func} ->
{Pid,Ref} = spawn_monitor(Func),
From ! {self(), Pid},
receive
{'DOWN',Ref, process, _, _} -> io:format("I lived for [calculated how long i lived]")
end
end.
What I'm trying to achieve here is
A = spawn(proc),
monitor(process,A).
However A might die before the second line executes.
If you spawn a process and it dies just before you create your monitor, you will still receive the DOWN message:
1> Pid = spawn(erlang,now,[]).
<0.35.0>
2> is_process_alive(Pid).
false
3> monitor(process, Pid).
#Ref<0.0.0.86>
4> flush().
Shell got {'DOWN',#Ref<0.0.0.86>,process,<0.35.0>,noproc}
As this shell session shows, we first spawn an intentionally short-lived process, and we use is_process_alive to verify that it's dead. We then create a monitor for the process, and then we flush the shell's message queue and see that it did indeed receive a DOWN message for the already-deceased process.
I saw message:
https://stackoverflow.com/a/4837832/1236509
with supervisor:
-module(root_sup).
-behaviour(supervisor).
-export([start_link/0]).
-export([init/1]).
start_link() ->
{ok, Pid} = supervisor:start_link({local, ?MODULE},
?MODULE, []),
erlang:unlink(Pid),
{ok, Pid}.
init(_Args) ->
RestartStrategy = {simple_one_for_one, 10, 60},
ChildSpec = {ch1, {ch1, start_link, []},
permanent, brutal_kill, worker, [ch1]},
Children = [ChildSpec],
{ok, {RestartStrategy, Children}}.
In console man calls:
{ok, ChildPid1} = root_sup:start_link().
when child pid changes how would ChildPid1 get new pid so always can use ChildPid1 with correct pid? Need way to link to part of supervisor creating child.
I would not try to access the child by Pid but instead register/2 the child process under a name, so it's accessible regardless of the actual Pid.
Using the code from the answer you reference, a simple way of doing this is to add register(ch1, self()), to the init procedure of the child. This would give, for ch1.erl:
init(_Args) ->
io:format("ch1 has started (~w)~n", [self()]),
% register a name to this process
register(child, self()),
{ok, ch1State}.
This registers the pid of the child self() to the name child
We can see it works:
1> root_sup:start_link().
{ok,<0.34.0>}
2> supervisor:start_child(root_sup, []).
ch1 has started (<0.36.0>)
{ok,<0.36.0>}
3> lists:filter(fun(X) -> X == child end, registered()).
[child]
we indeed have a process registered under the name of child.
4> gen_server:cast(child, calc).
result 2+2=4
and it is a correct process running the code from ch1.erl.
Let us crash this process, by invoking the bad code:
5> gen_server:cast(child, calcbad).
result 1/0
ok
ch1 has started (<0.41.0>)
6>
=ERROR REPORT==== 28-Oct-2012::01:31:30 ===
** Generic server <0.36.0> terminating
** Last message in was {'$gen_cast',calcbad}
** When Server state == ch1State
** Reason for termination ==
** {'function not exported',
[{ch1,terminate,
[{badarith,
[{ch1,handle_cast,2,[{file,"ch1.erl"},{line,27}]},
{gen_server,handle_msg,5,
[{file,"gen_server.erl"},{line,607}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,227}]}]},
ch1State],
[]},
{gen_server,terminate,6,[{file,"gen_server.erl"},{line,722}]},
{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,227}]}]}
So the child, the process <0.36.0> crashed, and a new child <0.41.0> was started to assume the duties of the deceased <0.36.0>. Since this new process is registered under the same name, calc will work again:
6> gen_server:cast(child, calc).
result 2+2=4
ok
Note that this does not guarantee that the gen_server:cast/2s always result in the execution of the corresponding code because the child might have been killed just now and the new process still was not started (registered in fact).
You might want to refer to the excellent Programming Erlang: Software for a Concurrent World by Joe Armstrong for more details about process registration, supervisors, OTP and more. Many details can also be found in the online documentation of OTP.
I'm using spawn_link but doesn't understand its behavior. Consider the following code:
-module(test).
-export([try_spawn_link/0]).
try_spawn_link() ->
spawn(fun() ->
io:format("parent: ~p~n", [Parent = self()]),
Client = spawn_link(fun() ->
io:format("child: ~p~n", [self()]),
spawn_link_loop(Parent)
end),
spawn_link_loop(Client)
end).
spawn_link_loop(Peer) ->
receive
quit ->
exit(normal);
Any ->
io:format("~p receives ~p~n", [self(), Any])
end,
spawn_link_loop(Peer).
From the Erlang documentation, a link is created between the calling process and the new process, atomically. However, I tested as follows and didn't notice the effect of the link.
1> test:try_spawn_link().
parent: <0.34.0>
<0.34.0>
child: <0.35.0>
2> is_process_alive(pid(0,34,0)).
true
3> is_process_alive(pid(0,35,0)).
true
4> pid(0,35,0) ! quit.
quit
5> is_process_alive(pid(0,35,0)).
false
6> is_process_alive(pid(0,34,0)).
true
1> test:try_spawn_link().
parent: <0.34.0>
<0.34.0>
child: <0.35.0>
2> is_process_alive(pid(0,34,0)).
true
3> is_process_alive(pid(0,35,0)).
true
4> pid(0,34,0) ! quit.
quit
5> is_process_alive(pid(0,35,0)).
true
6> is_process_alive(pid(0,34,0)).
false
In my understanding, if one peer of the link exits, the other peer exits (or is notified to exit). But the results seem different from my understanding.
EDIT: thanks to the answers of legoscia and Pascal.
It is because you have chosen to use exit(normal). In this case the other process will not stop. If you use for example exit(killed) then you will get the behavior you are expecting.
You can use monitor to get informed about normal termination.
As described in the "Error handling" section of the Processes chapter of the Erlang reference manual, a linked process exiting causes its linked processes to exit only if the exit reason is not normal. That's why OTP extensively uses the shutdown exit reason.
I want to test a mutex semaphore written in Erlang. The exported functions are:
start/0, -> To start the mutex server.
stop/0, -> To stop the mutex server.
wait/0, -> To put the semaphore in busy state.
signal/0, -> To free the semaphore.
Then, From an erlang console:
mutex:start().
mutex:wait().
How do I execute another mutex:wait() to test the semaphore?
I tried creating 2 erlang nodes (erl -sname), and using rpc:call(node, mutex, wait, []) I can do that but when i try the signal - rpc:call(node, mutex, signal, []) - it creates another Pid different from the one that makes the wait call, so the semaphore is never liberated.
Appreciate your help. Thanks!.
This is the code if needed * From Erlang Programming Book *
-module(mutex).
-export([start/0, stop/0]).
-export([wait/0, signal/0]).
-export([init/0]).
start() ->
register(mutex, spawn(?MODULE, init, [])).
stop() ->
mutex ! stop.
wait() ->
mutex ! {wait, self()},
receive ok -> ok end.
signal() ->
mutex ! {signal, self()},
ok.
init() ->
free().
free() ->
receive
{wait, Pid} ->
Pid ! ok,
busy(Pid);
stop ->
terminate()
end.
busy(Pid) ->
receive
{signal, Pid} ->
free()
end.
terminate() ->
receive
{wait, Pid} ->
exit(Pid, kill),
terminate()
after
0 -> ok
end.
From the shell do:
1> mutex:start().
2> mutex:wait().
3> spawn(fun () -> mutex:wait(), io:format("Got it\n"), mutex:signal() end).
4> mutex:signal().
Got it
5>
Off the top of my head so no return values here. You can also make it more interesting by spawning more processes and maybe including sleeps in them so they wait and signal in a more complex fashion.
You shouldn't need two whole erlang VMs to test this. I wrote a lock server in erlang a long time ago (provides such things via a simple tcp-based protocol) and had a fairly complete test for the core:
https://github.com/dustin/elock/blob/master/src/lock_serv_test.erl