【问题标题】:gen_server:call is failing with exception exitgen_server:call 因异常退出而失败
【发布时间】:2014-07-29 01:43:45
【问题描述】:

我在 OS X 10.9.2 上运行 Erlang R16B03-1 (erts-5.10.4)。 Erlang 是使用 brew 安装的。

我正在尝试运行一个 gen_server 模块。

-module(logger).
-author("evangelosp").

-behaviour(gen_server).

%% API
-export([start/0, stop/0, log/2]).

%% gen_server callbacks
-export([init/1,
  handle_call/3,
  handle_cast/2,
  handle_info/2,
  terminate/2,
  code_change/3]).

-define(SERVER, ?MODULE).

%%%===================================================================
%%% API
%%%===================================================================

start() -> gen_server:start_link({global, ?SERVER}, ?MODULE, [], []).

stop() -> gen_server:call(?MODULE, stop).

log(_Level, _MSG) -> gen_server:call(?MODULE, {add, {_Level, _MSG}}).

%%%===================================================================
%%% gen_server callbacks
%%%===================================================================

init([]) -> {ok, ets:new(?MODULE, [])}.

handle_call(_Request, _From, Table) -> {reply, {ok, ["Mplah!", _Request, _From, Table]}, Table}.

handle_cast(_Request, State) -> {noreply, State}.

handle_info(_Info, State) -> {noreply, State}.

terminate(_Reason, _State) -> ok.

code_change(_OldVsn, State, _Extra) -> {ok, State}.

在我正在运行的 erlang shell 中:

Eshell V5.10.4  (abort with ^G)
1> c(logger).
{ok,logger}
2> logger:start().
{ok,<0.40.0>}
3> logger:log(info, "Hello World").
** exception exit: {noproc,{gen_server,call,
                                       [logger,{add,{info,"Hello World"}}]}}
     in function  gen_server:call/2 (gen_server.erl, line 180)

而且我无法摆脱那个例外。通过查找异常消息,我实际上并没有找到任何有用的资源,但是 this 并没有太大帮助。

干杯。

【问题讨论】:

  • 顺便说一下,你应该从下划线开始,你只需要在函数体中没有使用的变量名。例如,在log/2 中,您同时使用了两个参数。
  • 哦,不错!欢呼

标签: erlang erlang-otp gen-server


【解决方案1】:

在您的代码start() -&gt; gen_server:start_link({global, ?SERVER}, ?MODULE, [], []). 中,您使用{global, ?SERVER},这意味着:

如果 ServerName={global,GlobalName} 则 gen_server 已注册 使用 global:register_name/2 全局作为 GlobalName。

所以当你向服务器发送消息时,你应该写log(_Level, _MSG) -&gt; gen_server:call({global, ?MODULE}, {add, {_Level, _MSG}}).。请参阅 erlang 文档:

call(ServerRef, Request, Timeout) -> 回复 类型: ServerRef = 名称 | {名称,节点} | {全球,全球名称} | ServerRef 可以是:

名称,如果gen_server是本地注册的,

{global,GlobalName},如果 gen_server 是全局注册的。

【讨论】:

  • 是的,你是对的。之后我以艰难的方式意识到这一点:) thx!
  • 我只查看了错误报告,而不是您的代码...真丢脸!仅当您想(现在或将来)创建 erlang 节点集群时,全局注册才有用;并且显式注册是无用的,如果您在 gen_server:start/ 中提供名称,它会自动完成
【解决方案2】:

您的服务器未注册,因此只能通过其 pid 访问。但是接口函数使用隐式宏 ?MODULE(编译时被 logger 代替)来访问它。

你需要改变你的接口函数,或者,在启动函数中注册服务器:

start() ->
  {ok,Pid} = gen_server:start_link({global, ?SERVER}, ?MODULE, [], []),
  register(?MODULE,Pid).

[edit] 感谢 Evalon,我在答案中进行了更正:o)

【讨论】:

  • 如果你能把你的线路固定到; {ok, Pid} = gen_server:start_link({global, ?SERVER}, ?MODULE, [], []), register(?MODULE, Pid). 确实是这样工作的,gen_server 不应该通过global 的选项来做到这一点吗??
  • 哦!!刚刚意识到,将其设置为global 是首要问题。感谢您的帮助!干杯!
猜你喜欢
  • 2020-05-09
  • 2020-11-14
  • 2018-03-12
  • 1970-01-01
  • 2014-02-06
  • 2015-06-15
  • 1970-01-01
  • 2022-08-13
  • 1970-01-01
相关资源
最近更新 更多