我有如下所示的gen_server。它在很大程度上起作用。但是,当我从shell启动它时,回复会立即回到shell提示符。我希望它们作为消息发送回shell pid,然后我会用flush()来查看它们。
为了让foo_worker将回复作为消息发送,我需要更改什么?
-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]).
答案 0 :(得分:3)
gen_server:call/2,3
的重点是将一个消息传递到gen_server
进程并接收其回复函数调用。如果您只想处理消息,请不要使用gen_server:call/2,3
,而是让调用者调用gen_server:cast/2
并在消息中包含调用者pid:
send(Worker, Ref, Counter) ->
gen_server:cast(Worker, {inc, Ref, Counter, self()}).
然后让gen_server:handle_cast/2
了解该消息并使用pid将回复发送回来电:
handle_cast({inc, Ref, Data, From}, Limit) ->
From ! {Ref, updated, Data+1},
{noreply, Limit-1}.
顺便说一句,请注意,当您选择这种方法时,您需要处理可能的失败。如果您将消息传递给gen_server
进程,但它在向您发送回复之前就已消失,则需要确保调用方不会坐下来等待永远不会到达的回复。执行此操作的最佳方法是使用monitor - 您可以让调用者在发送消息之前监视gen_server
进程,并在收到回复后监视demonitor进程。如果gen_server
进程终止,则调用者将收到DOWN
消息(有关详细信息,请参阅the monitor
documentation)。另请注意,通过执行此操作,您将重新实现gen_server:call/2,3
已为您执行的一系列操作。