如何在计时器上更新PID?

时间:2016-12-05 00:01:32

标签: erlang gen-server

我试图在10秒计时器上更新我的进程状态。

-define(INTERVAL, 3000).

start_link() ->
    gen_server:start_link(?MODULE, [], []).

action(Pid, Action) ->
  gen_server:call(Pid, Action).

init([]) -> 
  erlang:send_after(?INTERVAL, self(), trigger),
  {ok, temple:new()}.

我想做的就是打电话给这个

handle_call({fight}, _From, Temple) ->
  NewTemple = temple:fight(Temple),
  {reply, NewTemple, NewTemple};

所以我试试

handle_info(trigger, _State) ->
   land:action(self(), {fight}),
   erlang:send_after(?INTERVAL, self(), trigger);

但我得到

=ERROR REPORT==== 4-Dec-2016::19:00:35 ===
** Generic server <0.400.0> terminating
** Last message in was trigger
** When Server state == {{dict,0,16,16,8,80,48,
                               {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],
                                []},
                               {{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],
                                 []}}},
                         []}
** Reason for termination ==
** {function_clause,[{land,terminate,
                           [{timeout,{gen_server,call,[<0.400.0>,{fight}]}},
                            {{dict,0,16,16,8,80,48,
                                   {[],[],[],[],[],[],[],[],[],[],[],[],[],[],
                                    [],[]},
                                   {{[],[],[],[],[],[],[],[],[],[],[],[],[],
                                     [],[],[]}}},
                             []}],
                           [{file,"src/land.erl"},{line,47}]}

2 个答案:

答案 0 :(得分:1)

看来,对于land:action(self(), {fight}),您尝试将call发送到您当前处理trigger消息的同一gen_server。两个重要的事实将解释为什么这不起作用:

  • call始终等待返回结果。
  • gen_server是一个进程,进程一次只能处理一条消息。

在处理trigger消息时,您要对call回复自己并等待自己处理{fight}消息。但是,由于您正在处理trigger消息,因此您永远不会收到{fight}消息。你和你自己陷入了僵局。这就是你要暂停的原因。

P.S。发布SSCCE更有可能为您提供良好的答案。

答案 1 :(得分:0)

错误消息表示陆地服务器模块中没有terminate子句,编译陆地服务器模块时应该有警告。

调用terminate子句是因为在gen_server调用期间发生超时,参数(Pid = <0.400.0>, Message = {fight})land:action(self(), {fight}),行调用。对gen_server的调用必须在最长时间内完成,默认为5000ms,你必须减少在战斗行动中花费的时间。

请注意,增加服务器超时并不是一个好主意,因为gen_server调用正在阻塞:在执行gen_server调用期间,不会处理任何新消息,并且在您的示例中,它也阻止执行handle_info(trigger, _State)代码。

最后一点,子句handle_info(trigger, _State)应该返回{noreply,NewState}形式的元组,而最后一行erlang:send_after(?INTERVAL, self(), trigger);返回一个计时器引用,你必须修改这一行。