Erlang can not receive message from where it begins - erlang

There are two files here.
temp_converter() ->
receive
{convertToCelsius, {From, TempF}} ->
io:format("Temp-Server2 > Converter received message from ~w~n", [From]),
ConvertedTempC = (TempF-32)*5/9,
From ! finished,
From ! {converted, ConvertedTempC},
temp_converter();
{From, {convertToCelsius, TempF}} ->
io:format("Temp-Server > Converter received message from ~w~n", [From]),
ConvertedTempC = (TempF-32)*5/9,
From ! {converted, ConvertedTempC},
temp_converter()
end.
The other one is:
sensor(Temp, Temp_Node, Dis_Node) ->
receive
finished ->
io:foramt("finished");
% Receive the clock_tick from clock controller
clock_tick ->
io:format("Sensor_f received tick~n", []),
{temp_converter, Temp_Node} ! {convertToCelsius, {self(), Temp}};
% Receive the temperature which has been converted
{converted, ConvertedTemp} ->
io:format("Sensor_f received converted temperature~n", []),
{display_module, Dis_Node} ! {inCelsius, ConvertedTemp};
{'EXIT', From, Reason} ->
io:foramt("Temperature Server down!~nGot ~p~n", [{'EXIT', From, Reason}])
end.
Basically, the sensor will send message to temp_converter, which is implemented in "clock_tick ->". When temp_converter received message, it will output something and send message back. Here is the problem.
It does output something, but sensor can not receive message from temp_converter. Is there anything wrong with my code? I also tried to send "finished" message back, but it still does not work!!
How can I send message back? How can I change "From ! finished" and "From ! {converted, ConvertedTempC}," to be correct?

In the conversion:
{convertToCelsius, {From, TempF}} ->
io:format("Temp-Server2 > Converter received message from ~w~n", [From]),
ConvertedTempC = (TempF-32)*5/9,
From ! finished, %% Here you send to sensor the message 'finished'
From ! {converted, ConvertedTempC}, %% the conversion will be received %% after the first message (guaranteed by Erlang VM)
temp_converter();
And in the sensor:
finished ->
io:foramt("finished"); %% when you receive the first message, you print it
%% and leave the function. The next message will be lost
%% because you do not loop in the sensor function.
you only have to recall sensor(Temp, Temp_Node, Dis_Node) after the receive bloc and it should be fine.
Note that the message finished is useless in your case and that a simple call to a conversion function should do the job.

Related

How to make a gen_server reply with a message?

I have the gen_server shown below. It works for the most part. However when I start it from the shell the replies come right back to the shell prompt. I would have expected them to be sent as messages back to the shells pid and then I would use flush() to see them.
What do I have to change in order to have the foo_worker send its replies as messages ?
-module(foo_worker).
-behaviour(gen_server).
%% API
-export([start_link/1, start/1, init/1, send/3, die/1]).
-export([handle_call/3, handle_cast/2, handle_info/2, terminate/2]).
%%%-------------------------------------------------------------------
send(Worker, Ref, Counter) ->
gen_server:call(Worker, {inc, Ref, Counter}).
die(Worker) ->
gen_server:cast(Worker, die).
%%%-------------------------------------------------------------------
start_link(Limit) ->
gen_server:start_link(?MODULE, [Limit], []).
start(Limit) ->
gen_server:start(?MODULE, [Limit], []).
init([Limit]) ->
{ok, Limit}.
handle_call(_, _, Limit) when Limit =< 0 ->
exit({worker, eol});
handle_call({inc, Ref, Data}, From, Limit) ->
io:format("From ~p~n", [From]),
{reply, {Ref, updated, Data+1}, Limit - 1}.
handle_cast(die, _) ->
io:format("~p Dying ~n",[self()]),
exit(normal).
handle_info(Info, State) ->
io:format("Unkown message ~p for state ~p~n", [Info, State]).
terminate(Reason, State) ->
io:format("~p Died because ~p with state ~p~n", [self(), Reason, State]).
The whole point of gen_server:call/2,3 is to wrap into a function call the passing of a message into a gen_server process and the reception of its reply. If you want to deal only with messages, don't use gen_server:call/2,3 but rather have the caller invoke gen_server:cast/2 and include the caller pid in the message:
send(Worker, Ref, Counter) ->
gen_server:cast(Worker, {inc, Ref, Counter, self()}).
Then have gen_server:handle_cast/2 understand that message and use the pid send the reply back to the caller:
handle_cast({inc, Ref, Data, From}, Limit) ->
From ! {Ref, updated, Data+1},
{noreply, Limit-1}.
By the way, note that when you choose this sort of approach, you need to deal with possible failure. If you pass a message to the gen_server process but it dies before it sends you a reply, you need to make sure the caller doesn't sit and wait forever for a reply that will never arrive. The best way to do this is with a monitor — you can have the caller monitor the gen_server process before sending it a message and demonitor it once it receives the reply. If the gen_server process dies, the caller will get a DOWN message instead (see the monitor documentation for details). Also note that by doing this you're reimplementing a bunch of what gen_server:call/2,3 already does for you.

Erlang: push and pull from a shared queue

I need to maintain a shared queue where I can push data and a separate thread will periodically check and pull data from the queue if its not empty. I came up with the below solution where I can send data to the process and it adds up to a list. However, is there a cleaner / easier solution to do this ?
And im not sure how I may pull data from the below code.
-module(abc).
-export(queue/0).
queue() ->
receive
{push, Xmpp} ->
io:format("Push"),
queue(Xmpp);
{pull} ->
io:format("pull"),
queue()
end.
queue(E) ->
receive
{push, Xmpp} ->
io:format("Push ~w",[E]),
E1 = lists:append([E],[Xmpp]),
queue(E1);
{reset} ->
queue([])
end.
The code probably won't do exactly what you want as written. When you call queue/1 from the receive block ( queue(Xmpp); in line 7), queue/1 will fire and then wait for a message. Because this is not spawned in a separate process, queue/0 will block (since queue/1 is now waiting for a message that is never sent).
Also, queue/0 won't ever send anything back to the process sending it messages. It has no way of returning data to the sender.
The following will work (you will need to send messages to the pid returned by queue/0).
-module(abc).
-export([queue/0,queue/1]).
queue() ->
%% initialize an empty queue,
%% return the Pid to the caller
spawn(abc,queue,[[]]).
queue(E) when is_list(E) ->
receive
%% append the message value to the existing list
{push, Xmpp} ->
io:format("Pushing ~w to ~w~n",[Xmpp,E]),
E1 = lists:append(E,[Xmpp]),
queue(E1);
%% reset the queue
{reset} ->
queue([]);
%% return the value to the caller
%% "Pid" must be a Pid
{pull, Pid} when is_pid(Pid) ->
io:format("pull~n"),
Pid ! E,
queue(E)
end.
That's a problem with a straightforward solution in Erlang. Most of the time every erlang module you will be programming will be like a server, which will expect messages and will answer, you can have 0, 1 or mulitple servers running the same erlang module code. At the same time, you will be programming in the same module a client, which is an easy way to send messages to the server without having to know all the message format the server expect, instead you use functions, so instead of doing stuff like
Server ! {put, Value},
receive
{Server, {ok, Value}} ->
everything_ok;
{Server, {error, Reason}} ->
handle_error
end,
you end doing something like
my_module:put(Server, Value).
So you can create a server process in erlang with the code:
-module(abc).
-export([start/0, put/2, pop/1, reset/1, is_empty/1, loop/1]).
%% Client
start() ->
spawn(?MODULE, loop, [[]]).
put(Pid, Item) ->
Pid ! {self(), {put, Item}},
receive
{Pid, {ok, Item}} ->
Item;
{Pid, {error, Reason}} ->
{error, Reason}
after 500 ->
timeout
end.
pop(Pid) ->
Pid ! {self(), {pop}},
receive
{Pid, {ok, Item}} ->
Item;
{Pid, {error, Reason}} ->
{error, Reason}
after 500 ->
timeout
end.
reset(Pid) ->
Pid ! {self(), {reset}},
receive
{Pid, {ok}} ->
ok;
_ ->
error
after 500 ->
timeout
end.
is_empty(Pid) ->
Pid ! {self(), {is_empty}},
receive
{Pid, {true}} ->
true;
{Pid, {false}} ->
false;
_ ->
error
after 500 ->
timeout
end.
%% Server
loop(Queue) ->
receive
{From, {put, Item}} when is_pid(From) ->
From ! {self(), {ok, Item}},
loop(Queue ++ [Item]);
{From, {pop}} when is_pid(From) ->
case Queue of
[] ->
From ! {self(), {error, empty}},
loop(Queue);
[H|T] ->
From ! {self(), {ok, H}},
loop(T)
end;
{From, {reset}} when is_pid(From) ->
From ! {self(), {ok}},
loop([]);
{From, {is_empty}} when is_pid(From) ->
case Queue of
[] ->
From ! {self(), {true}},
loop(Queue);
_ ->
From ! {self(), {false}},
loop(Queue)
end;
_ ->
loop(Queue)
end.
and the code you end writting to use is simple as well:
(emacs#rorra)1> c("/Users/rorra/abc", [{outdir, "/Users/rorra/"}]).
{ok,abc}
(emacs#rorra)2> Q = abc:start().
<0.44.0>
(emacs#rorra)3> abc:is_empty(Q).
true
(emacs#rorra)4> abc:pop(Q).
{error,empty}
(emacs#rorra)5> abc:put(Q, 23).
23
(emacs#rorra)6> abc:is_empty(Q).
false
(emacs#rorra)7> abc:pop(Q).
23
(emacs#rorra)8> abc:pop(Q).
{error,empty}
(emacs#rorra)9> abc:put(Q, 23).
23
(emacs#rorra)10> abc:put(Q, 50).
50
(emacs#rorra)11> abc:reset(Q).
ok
(emacs#rorra)12> abc:is_empty(Q).
true
At the end to avoid all that repeated code you end using OTP and writting a gen_server for it.
I'm assuming you are building a queue on your own for learning, otherwise Erlang already has a good implementation for a Queue:
http://www.erlang.org/doc/man/queue.html
And the source code:
https://github.com/erlang/otp/blob/master/lib/stdlib/src/queue.erl

Receive after result not returned

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.

Erlang cast message to global gen_server

it's continue of previos question
I have gen_server:
start(UserName) ->
case gen_server:start({global, UserName}, player, [], []) of
{ok, _} ->
io:format("Player: " ++ UserName ++ " started");
{error, Error} ->
Error
end
...
How correctly send message to this gen_server. For example: in another file i make:
gen_server:cast(test, message).
In my gen_server file i have:
handle_cast(message, State) ->
io:format("Message receiving \r\n"),
{noreply, State};
I start my gen_server with test name:
server:start(test).
test started
when i call gen_server:cast(test, message). it is nothing output in shell. How can i check handle_cast calling or not?
Thank you.
Instead of
gen_server:cast(test, message).
write
gen_server:cast({global, test}, message).
If you register name as {global, name} you must call it as {global, name}
If your handler is called it will print "Message receiving \r\n" in shell. You made that with io:format call.

Erlang simple server problem

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.

Resources