如果您使用Erlang,如您所参考的其他问题所述...
您需要保存计时器引用,并调用erlang:cancel_timer/1来阻止它触发(如果尚未触发)。您必须注意这种“已经触发”的竞争条件,在您取消计时器时触发消息已经在您的消息队列中。您可能会关心这个问题,也可能不关心,但如果重要的是在触发被取消后永远不执行操作,则需要创建一个引用(或者您可以使用计数器)来设置定时消息,并且当您收到触发器时,您必须检查它是否与最新的触发器相关。
然后,其他问题中的代码变为:
-define(INTERVAL, 60000).
init(Args) ->
...
MyRef = erlang:make_ref(),
{ok, TRef} = erlang:send_after(?INTERVAL, self(), {trigger, MyRef}),
...
{ok, State#your_record{
timer = TRef,
latest = MyRef
}}.
handle_info({trigger, MyRef}, State = #your_record{latest=MyRef}) ->
...
MyRef = erlang:make_ref(),
{ok, TRef} = erlang:send_after(?INTERVAL, self(), trigger),
...
{ok, State#your_record{
timer = TRef,
latest = MyRef
}}.
handle_info({trigger, _OldRef}, State) ->
{ok, State}.
重置计时器的方法如下:
handle_info(reset, State = #your_record{timer=TRef}) ->
erlang:cancel_timer(TRef),
MyNewRef = erlang:make_ref(),
{ok, NewTRef} = erlang:send_after(?INTERVAL, self(), trigger),
{ok, State#your_record{
timer = NewTRef,
latest = MyNewRef
}}.
对于取消功能,调用可能更加合适,但这取决于您的应用,所以由您决定。
从技术上讲,取消计时器并不是必需的,因为一旦您使用新引用创建了新状态,即使旧计时器继续运行,当它触发时也会被忽略,但我认为最好还是进行清理工作。
Process.send_after(self(), :work, 60_000)
返回的计时器参考无法使用:timer.cancel(timer)
取消,因为它会返回{:error, :badarg}
。但是,我可以使用:erlang.cancel_timer(timer)
。 我正在使用 Elixir v1.1.1 版本。 - Jason HarrelsonProcess.cancel_timer(timer)
取消计时器。 - Mark Eric