2017-02-23 68 views
1

首先声明我正在学习erlang。这里根本不是专家。 虽然使用ETS做了一些例子,但我发现了一些我不理解的东西(即使搜索后)。有和没有外壳的ETS的不同行为

我在哪里创建

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

公共ETS然后我通过表格ID到其它过程的处理。当我这样做运行模块形成壳,一切都好。当我使用erl -noshell -s ...运行完全相同的模块时,或者甚至没有-noshell选项时,它都会失败。 我不断收到错误:badarg,好像表格不存在一样。该ID是正确通过,但该表实际上表现为私人!

从外壳或外壳交互运行模块有没有区别?

感谢


我加入,我使用尝试代码示例和调试问题。由于它是一个较大的软件(它基本上被剥离以找到问题),因此可能难以理解。

-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:查找,又都可以作为诠释他的交互式shell。

+0

你可以发布相关代码来重现错误情况吗? –

+0

完成了,我试图清理一下,只留下我用来试图理解我做错了什么的部分。 – Francesco

回答

2

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

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

+0

我想问题是正确的解决方案不那么直接。考虑到这只是一个例子,我只是使用不同的数据结构或封装在自己的过程中的ETS – Francesco

+0

有一个有趣的小论文[这里](http://steve.vinoski.net/blog/2011/03/ 23/dont-lose-your-ets-tables /)关于这个问题:“不要失去你的ets表”。 – Pascal