please could you enlighten me why following code is not using stdout if run using escript?
main(_) ->
spawn(fun() -> io:fwrite("blah") end).
Thanks!
fwrite still writes to stdout when running in an escript, the problem here is that your program terminates before the spawned process has had a chance to run!
The escript terminates as soon as the main function terminates, depending on how the virtual machine scheduled your spawned process you may or may not get the fwrite executed.
A simple workaround for your example is to add some synchronization:
main(_) ->
MainPid=self(),
spawn(fun() -> io:fwrite("blah"), MainPid ! done end),
receive
done ->
ok
end.
This makes the main process wait with termination until the spawned process has sent a message.
Related
Still working through Joe's book, and having hard time fully understanding monitors in general and spawn_monitor in particular. Here's the code I have; the exercise is asking to write a function that will start a process whose job is to print a heartbeat every 5 seconds, and then a function to monitor the above process and restart it. I didn't get to a restart part, because my monitor fails to even detect the process keeling over.
% simple "working" loop
loop_5_print() ->
receive
after 5000 ->
io:format("I'm still alive~n"),
loop_5_print()
end.
% function to spawn and register a named worker
create_reg_keep_alive(Name) when not is_atom(Name) ->
{error, badargs};
create_reg_keep_alive(Name) ->
Pid = spawn(ex, loop_5_print, []),
register(Name, Pid),
{Pid, Name}.
% a simple monitor loop
monitor_loop(AName) ->
Pid = whereis(AName),
io:format("monitoring PID ~p~n", [Pid]),
receive
{'DOWN', _Ref, process, Pid, Why} ->
io:format("~p died because ~p~n",[AName, Why]),
% add the restart logic
monitor_loop(AName)
end.
% function to bootstrapma monitor
my_monitor(AName) ->
case whereis(AName) of
undefined -> {error, no_such_registration};
_Pid -> spawn_monitor(ex, monitor_loop, [AName])
end.
And here's me playing with in:
39> c("ex.erl").
{ok,ex}
40> ex:create_reg_keep_alive(myjob).
{<0.147.0>,myjob}
I'm still alive
I'm still alive
41> ex:my_monitor(myjob).
monitoring PID <0.147.0>
{<0.149.0>,#Ref<0.230612052.2032402433.56637>}
I'm still alive
I'm still alive
42> exit(whereis(myjob), stop).
true
43>
It sure stopped the loop_5_print "worker" - but where's the line that the monitor was supposed to print? The only explanation that I see is that the message emitted by a process quitting in this manner isn't of the pattern on which I am matching inside monitor loop's receive. But that's the only pattern introduced in the book in this chapter, so I'm not buying this explanation..
spawn_monitor is not what you want here. spawn_monitor spawns a process and immediately starts monitoring it. When the spawned process dies, the process that called spawn_monitor gets a message that the process is dead. You need to call erlang:monitor/2 from the process that you want to receive the DOWN messages in, with the second argument being the Pid to monitor.
Just add:
monitor(process, Pid),
after:
Pid = whereis(AName),
and it works:
1> c(ex).
{ok,ex}
2> ex:create_reg_keep_alive(myjob).
{<0.67.0>,myjob}
I'm still alive
I'm still alive
I'm still alive
3> ex:my_monitor(myjob).
monitoring PID <0.67.0>
{<0.69.0>,#Ref<0.2696002348.2586050567.188678>}
I'm still alive
I'm still alive
I'm still alive
4> exit(whereis(myjob), stop).
myjob died because stop
true
monitoring PID undefined
Module test:
tester() ->
receive
X ->
erlang:display("message.."),
tester()
end.
initialize() ->
spawn_link(?MODULE, tester, []),
erlang:display("Started successfully.").
REPL:
length(erlang:processes()). -> 23
Pid = spawn_link(test, initialize, []).
length(erlang:processes()). -> 24
exit(Pid).
length(erlang:processes()). -> 24
It seems that the spawned tester process is still running! How do i make sure that when i exit my application, all spawn_link process are killed too?
Well, you are actually starting two Erlang processes, not one. The first one, to which you are sending the exit signal, dies before you even send the exit signal, so the exit has no effect.
The first process you start in the shell in this line:
Pid = spawn_link(test, initialize, []).
This process starts executing the initialize function, in which it starts the second process, and then it dies because there is nothing else to do. This is the process to which you are trying to send the exit signal.
To fix this simply return the correct Pid from the initialize function:
initialize() ->
Pid = spawn_link(?MODULE, tester, []),
erlang:display("Started successfully."),
Pid.
And start it directly:
Pid2 = test:initialize().
Then you will be able to kill it with exit(Pid2).
I'm currently reading Programming Erlang! , at the end of Chapter 13, we want to create a keep-alive process,
the example likes:
on_exit(Pid, Fun) ->
spawn(fun() ->
Ref = monitor(process, Pid),
receive
{'DOWN', Ref, process, Pid, Info} ->
Fun(Info)
end
end).
keep_alive(Name, Fun) ->
register(Name, Pid = spawn(Fun)),
on_exit(Pid, fun(_Why) -> keep_alive(Name, Fun) end).
but when between register/2 and on_exit/2 the process maybe exit, so the monitor will failed, I changed the keep_alive/2 like this:
keep_alive(Name, Fun) ->
{Pid, Ref} = spawn_monitor(Fun),
register(Name, Pid),
receive
{'DOWN', Ref, process, Pid, _Info} ->
keep_alive(Name, Fun)
end.
There also an bug, between spawn_monitor/2 and register/2, the process maybe exit. How could this come to run successfully? Thanks.
I'm not sure that you have a problem that needs solving. Monitor/2 will succeed even if your process exits after register/2. Monitor/2 will send a 'DOWN' message whose Info component will be noproc. Per the documentation:
A 'DOWN' message will be sent to the monitoring process if Item dies, if Item does not exist, or if the connection is lost to the node which Item resides on. (see http://www.erlang.org/doc/man/erlang.html#monitor-2).
So, in your original code
register assocates Name to the Pid
Pid dies
on_exit is called and monitor/2 is executed
monitor immediately sends a 'DOWN' message which is received by the function spawned by on_exit
the Fun(Info) of the received statement is executed calling keep_alive/2
I think all is good.
So why you did't want to use erlang supervisor behaviour? it's provides useful functions for creating and restarting keep-alive processes.
See here the example: http://www.erlang.org/doc/design_principles/sup_princ.html
In your second example, if process exits before registration register will fail with badarg. The easiest way to get around that would be surrounding register with try ... catch and handle error in catch.
You can even leave catch empty, because even if registration failed, the 'DOWN' message, will be sent.
On the other hand, I wouldn't do that in production system. If your worker fails so fast, it is very likely, that the problem is in its initialisation code and I would like to know, that it failed to register and stopped the system. Otherwise, it could fail and be respawned in an endless loop.
I am trying to write a first program in Erlang that effects message communication between a client and server. In theory the server exits when it receives no message from the client, but every time I edit the client code and run the server again, it executes the old code. I have to ^G>q>erl>[re-enter command] to get it to see the new code.
-module(srvEsOne).
%%
%% export functions
%%
-export([start/0]).
%%function definition
start()->
io:format("Server: Starting at pid: ~p \n",[self()]),
case lists:member(serverEsOne, registered()) of
true ->
unregister(serverEsOne); %if the token is present, remove it
false ->
ok
end,
register(serverEsOne,self()),
Pid = spawn(esOne, start,[self()]),
loop(false, false,Pid).
%
loop(Prec, Nrec,Pd)->
io:format("Server: I am waiting to hear from: ~p \n",[Pd]),
case Prec of
true ->
case Nrec of
true ->
io:format("Server: I reply to ~p \n",[Pd]),
Pd ! {reply, self()},
io:format("Server: I quit \n",[]),
ok;
false ->
receiveLoop(Prec,Nrec,Pd)
end;
false ->
receiveLoop(Prec,Nrec,Pd)
end.
receiveLoop(Prec,Nrec,Pid) ->
receive
{onPid, Pid}->
io:format("Server: I received a message to my pid from ~p \n",[Pid]),
loop(true, Nrec,Pid);
{onName,Pid}->
io:format("Server: I received a message to name from ~p \n",[Pid]),
loop(Prec,true,Pid)
after
5000->
io:format("Server: I received no messages, i quit\n",[]),
ok
end.
And the client code reads
-module(esOne).
-export([start/1, func/1]).
start(Par) ->
io:format("Client: I am ~p, i was spawned by the server: ~p \n",[self(),Par]),
spawn(esOne, func, [self()]),
io:format("Client: Now I will try to send a message to: ~p \n",[Par]),
Par ! {self(), hotbelgo},
serverEsOne ! {self(), hotbelgo},
ok.
func(Parent)->
io:format("Child: I am ~p, i was spawned from ~p \n",[self(),Parent]).
The server is failing to receive a message from the client, but I can't sensibly begin to debug that until I can try changes to the code in a more straightforward manner.
When you make modification to a module you need to compile it.
If you do it in an erlang shell using the command c(module) or c(module,[options]), the new compiled version of the module is automatically loaded in that shell. It will be used by all the new process you launch.
For the one that are alive and already use it is is more complex to explain and I think it is not what you are asking for.
If you have several erlang shells running, only the one where you compile the module loaded it. That means that in the other shell, if the module were previously loaded, basically if you already use the module in those shell, and even if the corresponding processes are terminated, the new version is ignored.
Same thing if you use the command erlc to compile.
In all these cases, you need to explicitly load the module with the command l(module) in the shell.
Your server loop contain only local function calls. Running code is changed only if there is remote (or external) function call. So you have to export your loop function first:
-export([loop/3]).
and then you have to change all loop/3 calls in function receiveLoop/3 to
?MODULE:loop(...)
Alternatively you can do same thing with receiveLoop/3 instead. Best practice for serious applications is doing hot code swapping by demand so you change loop/3 to remote/external only after receiving some special message.
Good day, i have following setup for my little service:
-module(mrtask_net).
-export([start/0, stop/0, listen/1]).
-define(SERVER, mrtask_net).
start() ->
Pid = spawn_link(fun() -> ?MODULE:listen(4488) end),
register(?SERVER, Pid),
Pid.
stop() ->
exit(?SERVER, ok).
....
And here is the repl excerpt:
(emacs#rover)83> mrtask_net:start().
<0.445.0>
(emacs#rover)84> mrtask_net:stop().
** exception error: bad argument
in function exit/2
called as exit(mrtask_net,ok)
in call from mrtask_net:stop/0
(emacs#rover)85>
As you see, stopping process produces error, process is stopping though.
What does this error mean and how to make thing clean ?
Not being an Erlang programmer and just from the documentation of exit (here), I'd say, that exit requires a process id as first argument whereas you are passing an atom (?SERVER) to it.
Try
exit(whereis(?SERVER), ok).
instead (whereis returns the process id associated with a name, see here)
You need to change the call to exit/2 as #MartinStettner has pointed out. The reason the process stops anyway is that you have started it with spawn_link. Your process is then linked to the shell process. When you called mrtask_net:stop() the error caused the shell process to crash which then caused your process to crash as they were linked. A new shell process is then automatically started so you can keep working with the shell. You generally do want to start your servers with spawn_link but it can cause confusion when your are testing them from the shell and they just "happen" to die.
I would suggest you to stick with OTP. It really gives you tons of advantages (I hardly can immagine the case where OTP doesn't benefit).
So, if you want to stop process in OTP you should do something like this for gen_server:
% process1.erl
% In case you get cast message {stopme, Message}
handle_cast({stopme, Message}, State) ->
% you will stop
{stop, normal, State}
handle_cast(Msg, State) ->
% do your stuff here with msg
{noreply, State}.
% process2.erl
% Here the code to stop process1
gen_server:cast(Pid, {stopme, "It's time to stop!"}),
More about it you can find here: http://www.erlang.org/doc/man/gen_server.html