I'm still trying to come to grips with Erlang messages, and while playing around with it, I came up with this case. It seems like it should work, but it just hangs indefinitely.
Can someone who is more used to Erlang please explain what I am doing wrong? And yes, I am aware that I don't even look at what is returned. This is the result of trying to reduce the code to isolate the problem.
-module(test).
-export([caller/2]).
callee(V1, V2, From) ->
From ! {V1, V2}.
caller(V1, V2) ->
spawn(fun() ->
callee(V1, V2, self()) end),
receive
_ ->
{V1, V2}
end.
If you assign the result of self() to a variable outside the function in the call to spawn and then pass in that variable instead of the literal self() then the message sent in callee will correctly be sent to the process running caller (the process waiting on receive).
This bit will help you understand where is the problem.
1> Self = self(), spawn(fun() -> io:format("Self: ~p, self():~p ~n", [Self, self()]) end).
Self: <0.83.0>, self():<0.85.0>
<0.85.0>
Related
When I register a process to an atom, I can send a message via the atom instead of the Pid interchangeably, which is convenient. However, pattern matching seems to treat Pid and atom as different entities, which is expected but inconvenient. In my example, the {Pid, Response} pattern does not match since Pid in this scope is an atom but the message sent as response contains the actual Pid.
Is there a preferred way to handle this?
The Program:
-module(ctemplate).
-compile(export_all).
start(AnAtom, Fun) ->
Pid = spawn(Fun),
register(AnAtom, Pid).
rpc(Pid, Request) ->
Pid ! {self(), Request},
receive
{Pid, Response} ->
Response;
Any ->
io:format("Finish (wrong):~p~n",[{Pid, Any}])
end.
loop(X) ->
receive
{Sender, Any} ->
io:format("Received: ~p~n",[{Sender, Any}]),
Sender ! {self(), "Thanks for contacting us"},
loop(X)
end.
The Shell:
Eshell V5.10.2 (abort with ^G)
1> c(ctemplate).
{ok,ctemplate}
2> ctemplate:start(foo, fun() -> ctemplate:loop([]) end).
true
3> ctemplate:rpc(foo, ["bar"]).
Received: {<0.32.0>,["bar"]}
Finish (wrong):{foo,{<0.40.0>,"Thanks for contacting us"}}
ok
4> whereis(foo).
<0.40.0>
Use references instead. The example you are suggesting is actually one of the reasons why refs are better for synchronous messages. Another reason is that sometimes you cannot guarantee that the received message is the one you are actually expecting.
So, your code will look like something
rpc(PidOrName, Request) ->
Ref = make_ref(),
PidOrName ! {{self(), Ref}, Request},
receive
{{Pid, Ref}, Response} ->
Response;
Any ->
io:format("Finish (wrong):~p~n",[{PidOrName, Any}])
end.
loop(X) ->
receive
{{Pid, Ref}, Any} ->
io:format("Received: ~p~n",[{Sender, Any}]),
Sender ! {{self(), Ref}, "Thanks for contacting us"},
end,
loop(X).
A couple notes about your and my code:
Note how I moved the last loop/1 call to the end of the function out of the receive block. Erlang does compile-time tail call optimizations, so your code should be fine, but it's a better idea to make tail calls explicitly – helps you to avoid mistakes.
You are probably trying to re-invent gen_server. The only two major differences between gen_server:call/2 and my code above are timeouts (gen_server has them) and that the reference is created by monitoring the remote process. This way, if the process dies before the timeout is thrown, we receive an immediate message. It's slower in many cases, but sometimes proves itself useful.
Overall, try to use OTP and read its code. It's good and gives you better ideas of how Erlang application should work.
rpc(Pid, Request) ->
Pid ! {self(), Request},
receive
{whereis(Pid), Response} ->
Response;
Any ->
io:format("Finish (wrong):~p~n",[{Pid, Any}])
end.
you can this function whereis():
whereis(RegName) -> pid() | port() | undefined
Types:
RegName = atom()
Returns the pid or port identifier with the registered name RegName. Returns undefined if the name is not registered.
For example:
whereis(db).
<0.43.0>
I have these code
start() ->
spawn(?MODULE, init, [self()]).
init(From) ->
spawn(?MODULE, broadcast, []).
broadcast() ->
Msg = "helloworld",
timer:sleep(10000),
broadcast().
When I test these code in Erlang shell, it give me undef error, I need to export broadcast function, I am just refuse
Code
spawn(?MODULE, init, [self()]).
means you will spawn process which initial call will be ?MODULE:init(self()) or more precisely equivalent of apply(?MODULE,init,[self()]). ?MODULE is macro evaluated to current module name but anyway It is external function call so this function have to be exported even there is ?MODULE used. In contrary
spawn(fun() -> init(self()) end).
is spawn with initial call to the func fun() -> init(self()) end which calls init/1 with result of function self(). It is local call which means init/1 may not be exported. There is another issue with it when self() is performed inside new process so you have to write
Self = self(), spawn(fun() -> init(Self) end).
to achieve same effect as in spawn(?MODULE, init, [self()]) where self() is evaluated as parameter of spawn/3.
well, the function broadcast is executed in a process. This function must therefore be accessible to all processes. Even though the same piece of source code, in the same module, spawns a process which goes to execute a function from the same module, that function must be exported out of that module to make it accessible.
That brings me to the difference between spawn(fun() -> broadcast() end). and spawn(?MODULE, broadcast, []). The later is called Spawning with MFA. In this method, the function must be exported out of the module so that it can be executed. The former is however unique, its a fun.
To understand this method: spawn(fun() -> broadcast() end)., we need to compare it with this one: spawn(fun() -> ?MODULE:broadcast() end). . Now, lets talk about the later of the two
spawn(fun() -> ?MODULE:broadcast() end). Now, here, if the function broadcast IS NOT exported in the module: ?MODULE, the process will crash. Note that in this case, the function is in the very module in which this piece of source code is written. spawn(fun() -> broadcast() end).In this case, the function must be in the very module in which this piece of source code is written. However, my thinking is this, the compiler converts this to the one above so that the spawned process is told that the function you are looking for is in module ?MODULE.I am not really a guru at compilers or run time systems, but i guess you will use this answer. My Strong advice is that in most of your source code, use this spawn(fun() -> ?MODULE:broadcast() end). or spawn(fun() -> some_module:broadcast() end). even though the piece of code or the function resides in that same very module than this: spawn(fun() -> broadcast() end).. From my personal experience the code becomes manageable and understandable. I get this nice illusion that a spawned process has to go and find the function from the specified module, and then execute with the given arguments.
Look more carefully at the warnings:
test.erl:8: Warning: function init/1 is unused
test.erl:8: Warning: variable 'From' is unused
test.erl:11: Warning: function broadcast/0 is unused
test.erl:12: Warning: variable 'Msg' is unused
The compiler thinks that your other functions are unused and never compiles them. Try this instead:
start() ->
spawn(fun() -> init(self()) end).
init(From) ->
spawn(fun() -> broadcast() end).
This line fails with a badarg exception:
register(myproc, self()),
The documentation says that self/0 returns a pid and that register/2 takes a pid. So what gives?
Edit: No, seriously, it's not already registered, it's not a reserved atom, and it works when I register it from the process that's spawning it.
Oh weird! Okay, I got some more clues. When I move the call to register() around to different places, sometimes it works and sometimes it breaks. Here's my sample code. Run it before you call me crazy. :-)
-module(pingpong).
-export([start/1, ping/2, pong/0]).
ping(N, Pong_Pid) ->
link(Pong_Pid),
pingr(N, Pong_Pid).
pingr(0, _) ->
io:format("Ping exiting~n", []),
exit(ping);
pingr(N, Pong_Pid) ->
Pong_Pid ! {ping, self()},
receive
pong ->
io:format("Ping received pong~n", [])
end,
pingr(N - 1, Pong_Pid).
pong() ->
%% This one works.
%%register(pong, self()),
process_flag(trap_exit, true),
pongr().
pongr() ->
%% This one fails.
register(pong, self()),
receive
{ping, Ping_PID} ->
io:format("Pong received ping~n", []),
Ping_PID ! pong,
pongr();
{'EXIT', From, Reason} ->
io:format("pong exiting, got ~p~n", [{'EXIT', From, Reason}])
end.
start(Ping_Node) ->
PongPID = spawn(pingpong, pong, []),
spawn(Ping_Node, pingpong, ping, [3, PongPID]).
If the process is already registered, it will throw a badarg. There is also some other cases that causes this, like the name is already used. See the erlang:register/2 docs for more.
EDIT
It's great that you posted code to reproduce your problem.
So, the first time you enter pongr/0 you will register self(). When you receive a message, you will process it and call pongr/0 again. The second time you enter pongr/0 you try to register self(), which fails because it's already registered.
Also, if you want to use register a large number of processes, you should look into gproc. register/2 requires an atom as the key and there is a limit of around one million atoms, unless you explicitly change it. See the efficiency guide. gproc can also run distributed and may thus be used instead of the global module.
is myproc already registered?
first call should succeed, additional calls will cause badarg exception.
1> register(myproc, self()).
true
2> myproc ! foo.
foo
3> flush().
Shell got foo
ok
4> register(myproc, self()).
** exception error: bad argument
in function register/2
called as register(myproc,<0.30.0>)
I have been trying to learn Erlang and came across some code written by Joe Armstrong:
start() ->
F = fun interact/2,
spawn(fun() -> start(F, 0) end).
interact(Browser, State) ->
receive
{browser, Browser, Str} ->
Str1 = lists:reverse(Str),
Browser ! {send, "out ! " ++ Str1},
interact(Browser, State);
after 100 ->
Browser ! {send, "clock ! tick " ++ integer_to_list(State)},
interact(Browser, State+1)
end.
It is from a blog post about using websockets with Erlang: http://armstrongonsoftware.blogspot.com/2009/12/comet-is-dead-long-live-websockets.html
Could someone please explain to me why in the start function, he spawns the anonymous function start(F, 0), when start is a function that takes zero arguments. I am confused about what he is trying to do here.
Further down in this blog post (Listings) you can see that there is another function (start/2) that takes two arguments:
start(F, State0) ->
{ok, Listen} = gen_tcp:listen(1234, [{packet,0},
{reuseaddr,true},
{active, true}]),
par_connect(Listen, F, State0).
The code sample you quoted was only an excerpt where this function was omitted for simplicity.
The reason for spawning a fun in this way is to avoid having to export a function which is only intended for internal use. One problem with is that all exported functions are available to all users even if they only meant for internal use. One example of this is a call-back module for gen_server which typically contains both the exported API for clients and the call-back functions for the gen_server behaviour. The call-back functions are only intended to be called by the gen_server behaviour and not by others but they are visible in the export list and not in anyway blocked.
Spawning a fun decreases the number of exported internal functions.
In Erlang, functions are identified by their name and their arity (the number of parameters they take). You can have more than one function with the same name, as long as they all have different numbers of parameters. The two functions you've posted above are start/0 and interact/2. start/0 doesn't call itself; instead it calls start/2, and if you take a look further down the page you linked to, you'll find the definition of start/2.
The point of using spawn in this way is to start a server process in the background and return control to the caller. To play with this code, I guess that you'd start up the Erlang interpreter, load the script and then call the start/0 function. This method would then start a process in the background and return so that you could continue to type into the Erlang interpreter.
A common pattern in Erlang is the recursive loop that maintains state:
loop(State) ->
receive
Msg ->
NewState = whatever(Msg),
loop(NewState)
end.
Is there any way to query the state of a running process with a bif or tracing or something? Since crash messages say "...when state was..." and show the crashed process's state, I thought this would be easy, but I was disappointed that I haven't been able to find a bif to do this.
So, then, I figured using the dbg module's tracing would do it. Unfortunately, I believe because these loops are tail call optimized, dbg will only capture the first call to the function.
Any solution?
If your process is using OTP, it is enough to do sys:get_status(Pid).
The error message you mentions is displayed by SASL. SASL is an error reporting daemon in OTP.
The state you are referring in your example code is just an argument of tail recursive function. There is no way to extract it using anything except for tracing BIFs. I guess this would be not a proper solution in production code, since tracing is intended to be used only for debug purposes.
Proper, and industry tested, solution would be make extensive use of OTP in your project. Then you can take full advantage of SASL error reporting, rb module to collect these reports, sys - to inspect the state of the running OTP-compatible process, proc_lib - to make short-lived processes OTP-compliant, etc.
It turns out there's a better answer than all of these, if you're using OTP:
sys:get_state/1
Probably it didn't exist at the time.
It looks like you're making the problem out of nothing. erlang:process_info/1 gives enough information for debugging purposes. If your REALLY need loop function arguments, why don't you give it back to caller in response to one of the special messages that you define yourself?
UPDATE:
Just to clarify terminology. The closest thing to the 'state of the process' on the language level is process dictionary, usage of which is highly discouraged. It can be queried by erlang:process_info/1 or erlang:process/2.
What you actually need is to trace process's local functions calls along with their arguments:
-module(ping).
-export([start/0, send/1, loop/1]).
start() ->
spawn(?MODULE, loop, [0]).
send(Pid) ->
Pid ! {self(), ping},
receive
pong ->
pong
end.
loop(S) ->
receive
{Pid, ping} ->
Pid ! pong,
loop(S + 1)
end.
Console:
Erlang (BEAM) emulator version 5.6.5 [source] [smp:2] [async-threads:0] [kernel-poll:false]
Eshell V5.6.5 (abort with ^G)
1> l(ping).
{module,ping}
2> erlang:trace(all, true, [call]).
23
3> erlang:trace_pattern({ping, '_', '_'}, true, [local]).
5
4> Pid = ping:start().
<0.36.0>
5> ping:send(Pid).
pong
6> flush().
Shell got {trace,<0.36.0>,call,{ping,loop,[0]}}
Shell got {trace,<0.36.0>,call,{ping,loop,[1]}}
ok
7>
{status,Pid,_,[_,_,_,_,[_,_,{data,[{_,State}]}]]} = sys:get_status(Pid).
That's what I use to get the state of a gen_server. (Tried to add it as a comment to the reply above, but couldn't get formatting right.)
As far as I know you cant get the arguments passed to a locally called function. I would love for someone to prove me wrong.
-module(loop).
-export([start/0, loop/1]).
start() ->
spawn_link(fun () -> loop([]) end).
loop(State) ->
receive
Msg ->
loop([Msg|State])
end.
If we want to trace this module you do the following in the shell.
dbg:tracer().
dbg:p(new,[c]).
dbg:tpl(loop, []).
Using this tracing setting you get to see local calls (the 'l' in tpl means that local calls will be traced as well, not only global ones).
5> Pid = loop:start().
(<0.39.0>) call loop:'-start/0-fun-0-'/0
(<0.39.0>) call loop:loop/1
<0.39.0>
6> Pid ! foo.
(<0.39.0>) call loop:loop/1
foo
As you see, just the calls are included. No arguments in sight.
My recommendation is to base correctness in debugging and testing on the messages sent rather than state kept in processes. I.e. if you send the process a bunch of messages, assert that it does the right thing, not that it has a certain set of values.
But of course, you could also sprinkle some erlang:display(State) calls in your code temporarily. Poor man's debugging.
This is a "oneliner" That can be used in the shell.
sys:get_status(list_to_pid("<0.1012.0>")).
It helps you convert a pid string into a Pid.