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

Posted

技术标签:

【中文标题】有壳和没有壳的 ETS 的不同行为【英文标题】:Different behaviour of ETS with and without a shell 【发布时间】:2017-07-13 22:11:52 【问题描述】:

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

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

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

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

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

谢谢


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

-record(loop_state, 
        commands
        ).

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

loop(Socket, LoopState = #loop_statecommands = 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 运行。

【问题讨论】:

能否贴出相关代码重现错误情况? 完成了,我试着清理了一下,只留下我正在使用的部分,试图了解我做错了什么。 【参考方案1】:

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

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

【讨论】:

我想问题是正确的解决方案不太直接。考虑到这只是一个例子,我只是使用不同的数据结构或将 ETS 封装在自己的进程中 有一篇关于这个主题的有趣的小论文here:“不要丢失你的ets表”。

以上是关于有壳和没有壳的 ETS 的不同行为的主要内容,如果未能解决你的问题,请参考以下文章

壳的加载过程

如何利用花生壳和VisualSVN Server建立远程代码仓库

bugku love

程序脱壳是啥意思?

按钮的点击事件没有不同的行为

为啥在循环内调用 publishProgress 并多次调用(没有循环)会显示不同的行为?