有和没有 shell 的 ETS 的不同行为

Different behaviour of ETS with and without a shell

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

我有一个创建 public ETS 的过程

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

然后我将 TableID 传递给其他进程。当我这样做 运行 将模块形成 shell 时,一切正常。当我 运行 与 erl -noshell -s ... 甚至没有 -noshell 选项完全相同的模块时,它会失败。 我一直收到 error:badarg 就好像 tabled 不存在一样。 ID 正确通过,但 table 实际上表现为私有!

运行ning 模块与 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.

当我删除 "offending command" ets:lookup 时,一切都将再次作为交互式 shell。

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

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