Can someone please explain this line by line?
Many many thanks.
run() ->
Pid = spawn(fun ping/0),
Pid ! self(),
receive
pong -> ok
end.
ping() ->
receive
From -> From ! pong
end.
Line by line:
run() ->
Declare the function run/0
Pid = spawn(fun ping/0),
Spawns new process with initialization function ping/0 and store its pid to variable Pid
Pid ! self(),
Sends message containing the pid of current process (result of self/0 call) to the process which pid is stored in variable Pid
receive
Waits for a message (or amount of time if there is after clause)
pong -> ok
If there is a received message pong, return value ok
end.
End of receive clause and dot also means there is end of function run/0
ping() ->
Declares the function ping/0
receive
Waits for a message ...
From -> From ! pong
When receiving anything, store it in variable From and then send message pong to the process determined by value in From (pid of process executing run/0 function in this case)
end.
End of receive and also ping/0 function
Related
I have a gen_server (my_gen_server.erl) that is started by another server (i.e. ejabberd)
Inside my_gen_server.erl, I start another server which handles HTTP2 calls like this:
{ok, ServerPid} = apns:connect(cert, my_first_connection).
Now, my_gen_server is receiving messages both from ejabberd and ServerPid which I handle as follows:
1. handle_info({reconnecting, ServerPid}=Msg, State) -> %% do Something
2. handle_info({connection_up, ServerPid}=Msg, State) -> %% do Something
3. handle_info(#offline_msg{...} = _Msg, State) -> %% do Something
So 1 & 2 are sent by ServerPid and 3 is sent by ejabberd. This is working but I am not sure about the correct behavior. So,
My question is:
Is this correct gen_server behavior to receive/handle messages from multiple client processes?
Please help.
Any process that has the gen_server's pid can send the gen_server a message using !, which will be handled by the gen_server's function:
handl_info()
Any process that has the gen_server's pid can call the functions:
call(GenServerPid, Msg)
cast(GenServerPid, Msg)
which will be handled by the gen_server functions:
handle_call()
handle_cast()
In elixir, there is a module called Agent, which is just a gen_server that stores State, like a counter. Multiple processes can update the counter and retrieve the current count. Of course, some process has to start the gen_server, then pass the pid to the other processes that want to update/retrieve the count.
gen_server documentation on Module:terminate callback says:
Even if the gen_server process is not part of a supervision tree, this
function is called if it receives an 'EXIT' message from its parent.
Reason is the same as in the 'EXIT' message.
Here is my handle_info and terminate function:
handle_info(UnknownMessage, State) ->
io:format("Got unknown message: ~p~n", [UnknownMessage]),
{noreply, State}.
terminate(Reason, State) ->
io:format("Terminating with reason: ~p~n", [Reason]).
I start this server using gen_server:start. I assume when I call erlang:exit(Pid, fuckoff), it should call terminate callback function. But it shows:
Got unknown message: {'EXIT',<0.33.0>,fuckoff}
Which means it is calling handle_info. But when I call gen_server:stop, everything works as mentioned in documentation. I'm calling my gen_server from shell. Would you please clarify this?
[UPDATE]
Here is source code of decode_msg function inside gen_server. If it receives any 'EXIT' message it should call terminate function:
decode_msg(Msg, Parent, Name, State, Mod, Time, Debug, Hib) ->
case Msg of
{system, From, Req} ->
sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug,
[Name, State, Mod, Time], Hib);
{'EXIT', Parent, Reason} ->
terminate(Reason, Name, Msg, Mod, State, Debug);
_Msg when Debug =:= [] ->
handle_msg(Msg, Parent, Name, State, Mod);
_Msg ->
Debug1 = sys:handle_debug(Debug, fun print_event/3,
Name, {in, Msg}),
handle_msg(Msg, Parent, Name, State, Mod, Debug1)
end.
In my case it doesn't call terminate function.
[UPDATE]
When I start gen_server using gen_server:start_link(), sending an exit signal using erlang:exit(Pid, Reason) will result in calling terminate call back function which is an expected behaviour. It seems there is a difference in interpreting an exit signal whether a process is linked to its parent or not.
Short answer:
If you call the exit/2 function from inside the gen_server actor, it behaves as expected based on the documentation and the terminate/2 callback will be called.
Long answer:
When you send the exit message from the shell, the Parent value of exit tuple is set to the shell process id, on the other hand when you start the gen_server process form shell its Parent value is set to its own process id, not the shell process id, therefore when it gets the exit message it doesn't match the second clause of the receive block in decode_msg/8 function so the terminate/6 function is not called and finally the next clause is matched which is calling handle_msg/5 function.
Recommendation:
For getting the terminate/3 callback called even by sending an exit message to the gen_server process, you can trap the exit message in handle_info/2 and then return with stop tuple as follows:
init([]) ->
process_flag(trap_exit, true),
{ok, #state{}}.
handle_info({'EXIT', _From, Reason}, State) ->
io:format("Got exit message: ~p~n", []),
{stop, Reason, State}.
terminate(Reason, State) ->
io:format("Terminating with reason: ~p~n", [Reason]),
%% do cleanup ...
ok.
When you start your gen_server, its a simple process, so, erlang:exit/1 or erlang:exit/2 work as expected.
If Pid is not trapping exits, Pid itself exits with exit reason Reason.
If Pid is trapping exits, the exit signal is transformed into a message {'EXIT', From, Reason} and delivered to the message queue of Pid.
So, currently your code trap 'EXIT' signal because this one is send like any other message into the mailbox and match handle_info/2 wildcard pattern.
If you want more information about that, you can read gen_server source code and see how it works. You can also find your problem described in this code.
An example of this would be:
myFunction()
receive
msg1 -> io:format("Message 1!~n"),
self() ! msg1,
myFunction();
msg2 -> io:format("Message 2!~n")
end.
I learnt to do my messages like msg1; but recently I made an error and compiled my code similar to msg2. When msg2 occurs, what happens afterwards? Does the process just sit at that same receive after msg2 and wait for other messages?
Why don't you try it yourself?
If you don't call the function after receiving msg2, then there is nothing more to execute and your process will quit.
Does the process just sit at that same receive after msg2 and wait for other messages?
No. You need to call the function again. The recursion creates a loop.
When msg2 occurs, what happens afterwards?
Message 2!\n is printed and myFunction/0's code is no longer executed, and if the current process has nothing more to do it exits.
if you don't call the function again at the end of a receive block, the process will die.(if you case, if you send msg2 to the process), but if you send other message(except for msg1 and msg2), the process will wait, and the messages are stored in the process's message queue.
-module(wy).
-compile(export_all).
myFunction() ->
receive
msg1 ->
io:format("Message 1!~n"),
self() ! msg1,
myFunction();
msg2 ->
io:format("Message 2!~n")
end.
parent() ->
Pid = spawn(fun myFunction/0),
register(myFunction, Pid),
erlang:monitor(process, Pid),
receive
Res -> io:format("Receive ~p~n", [Res])
end.
main() ->
spawn(fun() -> parent() end).
first you need execute wy:main().
(1) if you execute myFunction ! msg22., you can find the process myFunction is still alive, and use this command erlang:process_info(whereis(myFunction), messages)., you can find the message msg22 is stored in the message queue.
(2) if you execute myFunction ! msg2., you can get this output
Message 2!
Receive {'DOWN',#Ref<0.0.0.108>,process,<0.48.0>,normal}
msg2
from this output you can know the process myFunction is died.
(3) if you execute myFunction ! msg1, the process will go into endless loop。
The other answers are almost correct. If you don't do a recursive call after receiving msg2 then the function will end and you will go back to the caller of myFunction/0. It will then depend on the caller what happens. If this is the last thing to do in the process then the process will terminate with reason normal, otherwise it will continue processing.
The thing to remember is that each call to receive will just process one message so if you want to keep processing messages then you must do repeated calls to receive. Hence the recursion in myFunction.
Given a function:
%% #doc Retrieves client's state.
-spec(state(pid()) -> atom()).
state(Pid) when is_pid(Pid) ->
case process_info(Pid) of
undefined ->
undefined;
_Else ->
Pid ! {state, self()},
receive
{state, State} ->
State
after
1000 ->
undefined
end
end.
It works as expected for dead pids and for alive clients:
> client:state(A).
undefined
> client:state(Pid).
online
But for some reason returns Pid if process Pid will not reply his status during 1 second:
> client:state(self()).
<0.172.0>
I'm expecting 'undefined' atom there.
How can I fix this code?
This happens because you are receiving the message you sent. Your function is running on the shell process and sends itself the {state, self()} message. Right after sending the message, it receives the message and the function ends with State, which is the self() pid you sent.
I hope I've not been too confusing.
As I learn Erlang, I'm trying to solve ex. 4.1 ("An Echo server") from "Erlang Programming" book (by O'Reilly) and I have a problem.
My code looks like that:
-module(echo).
-export([start/0, print/1, stop/0, loop/0]).
start() ->
register(echo, spawn(?MODULE, loop, [])),
io:format("Server is ready.~n").
loop() ->
receive
{print, Msg} ->
io:format("You sent a message: ~w.~n", [Msg]),
start();
stop ->
io:format("Server is off.~n");
_ ->
io:format("Unidentified command.~n"),
loop()
end.
print(Msg) -> ?MODULE ! {print, Msg}.
stop() -> ?MODULE ! stop.
Unfortunatelly, I have some problems. Turning on works as expected, it spawns a new process and display "Server is ready" message. But when I try to use print function (like echo:print("Some message."). that, for example) I got result, but it doesn't work like I'd like to. It prints my message as a list (not as a string) and it generates
=ERROR REPORT==== 18-Jul-2010::01:06:27 ===
Error in process <0.89.0> with exit value: {badarg,[{erlang,register,[echo,<0.93.0>]},{echo,start,0}]}
error message.
Moreover, when I try to stop server by echo:stop() I got another error
** exception error: bad argument
in function echo:stop/0
Could anybody explain me, what's going on here ? I am new to Erlang and it seems to be quite difficult to grasp for me at this time.
When your loop/0 function receive print message you call start/0 again which spawns new process and trying to register it as echo again. It causes your server dies and new one is not registered as echo, so you can't send message to it by print/1 function any more.
loop() ->
receive
{print, Msg} ->
io:format("You sent a message: ~w.~n", [Msg]),
loop(); % <-- just here!
stop ->
io:format("Server is off.~n");
_ ->
io:format("Unidentified command.~n"),
loop()
end.