0

首先声明我正在学习 erlang。这里根本不是专家。在使用 ETS 制作一些示例时,我遇到了一些我不理解的东西(即使在搜索之后)。

我有一个创建公共 ETS 的过程

TableID = ets:new(tablename, [public])}

然后我将 TableID 传递给其他进程。当我从外壳运行模块时,一切正常。当我使用 erl -noshell -s ... 甚至没有 -noshell 选项运行完全相同的模块时,它会失败。我不断收到错误:badarg,好像表格不存在一样。ID 正确通过,但表实际上表现得像私有的!

从 shell 交互运行模块与不运行模块有区别吗?

谢谢


我正在添加我用来尝试调试问题的代码示例。由于它是一个更大的软件的一部分(而且它基本上是为了找到问题而被剥离的),它可能很难理解。

-record(loop_state, {
        commands
        }).

start() ->
    LoopState = #loop_state{commands = ets:new(commands, [public])},
    tcpserver_otp_backend:start(?MODULE, 7000, {?MODULE, loop}, LoopState).

loop(Socket, LoopState = #loop_state{commands = Commands}) ->
    case gen_tcp:recv(Socket, 0) of
        {ok, Data} ->
            % the call below fails, no error generated, AND only in non interactive shell
            A = newCommand(Commands, Data), 
            gen_tcp:send(Socket, A),
            loop(Socket, LoopState);
        {error, closed} ->
            ok
    end.


 newCommand(CommandTableId, Command) ->
    case ets:lookup(CommandTableId,Command) of 
        [] ->
            _A = ets:insert(CommandTableId, {Command, 1}),
            <<1, "new", "1">>; % used for testing
        _ ->
            <<1, "old", "1">> % used for testing
    end.

当我删除“有问题的命令”ets:lookup 时,一切都再次作为交互式 shell 工作。

4

1 回答 1

1

问题似乎是您在 start() 函数中创建了 ets 表。ets 表有一个所有者(默认情况下是创建过程),当所有者死亡时,该表将被删除。当您通过将 -s 传递给 erl 从命令行运行 start/0 函数时,该所有者进程将是 Erlang 内核中的某个内部进程,它是处理启动序列的一部分。无论您是否通过 -noshell,该过程都可能是暂时的,并且会在查找函数有时间执行之前终止,因此当查找最终发生时该表不再存在。

创建 ets 表的正确位置是在您启动的 gen_server 的 init() 回调函数中。如果它应该是由多个进程访问的公共 est 表,那么您可能希望创建一个单独的服务器进程,其任务是拥有该表。

于 2017-02-23T13:35:55.900 回答