当前位置: 动力学知识库 > 问答 > 编程问答 >

erlang - 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.

分享给朋友:
您可能感兴趣的文章:
随机阅读: