Erlang ETS插入/ 2错误

时间:2016-05-19 08:27:11

标签: concurrency erlang erlang-shell ets

我正在尝试创建一个简单的Erlang进程,可以访问ETS模块。

我的源代码包括:

  1. 创建流程:

    start_message_channel() ->
        Table = ets:new(messages, [ordered_set, named_table]),
        Channel = spawn(?MODULE, channel, []),
        {Channel, {table, Table}}.
    
  2. 流程逻辑:

    channel() ->
        receive
            {Sender, {send_message, {Message, Table}}} ->
                ets:insert(Table, {message, Message}),
                Sender ! {self(), {status, success}};
            {Sender, {receive_message, Table}} ->
                {message, Message} = ets:first(Table),
                Sender ! {self(), {status, {success, Message}}};
            _ ->
                throw(incorrect_protocol_exception)
    end.
    
  3. 与流程沟通

    send_message_to_message_channel({Channel, {table, Table}}, Message) ->
        Channel ! {self(), {send_message, {Message, Table}}},
        receive
            {Channel, {status, success}} ->
                io:format("Message sent!~n");
            {Channel, {status, failure}} ->
                io:format("Message failed to send!~n");
            _ ->
                throw(incorrect_protocol_exception)
    end.
    
    receive_message_from_message_channel({Channel, {table, Table}}) ->
        Channel ! {self(), {receive_message, Table}},
        receive
            {Channel, {status, {success, Message}}} ->
                io:format(Message);
            {Channel, {status, failure}} ->
                io:format("Message failed to receive!~n");
            _ ->
                throw(incorrect_protocol_exception)
    end.
    
  4. 在Erlang终端中执行函数调用时,我收到错误:

        1> cd("C:/Users/dauma").                    
        C:/Users/dauma
        ok
        2> c(message_channel).
        {ok,message_channel}
        3> Object = message_channel:start_message_channel().
        {<0.59.0>,{table,messages}}
        4> message_channel:send_message_to_message_channel(Object, "Hello World!").
    
        =ERROR REPORT==== 19-May-2016::11:09:27 ===
        Error in process <0.59.0> with exit value:
        {badarg,[{ets,insert,[messages,"Hello World!"],[]},
            {message_channel,channel,0,
                [{file,"message_channel.erl"},{line,35}]}]}
    

    有谁能告诉我,问题可能出在哪里?

1 个答案:

答案 0 :(得分:8)

ETS表由Erlang进程拥有,并具有访问控制。默认情况下,该表为protected,并且只能由拥有它的进程写入,但可以从其他进程读取。

如果您想要从其他流程读取和写入,请使用public

Table = ets:new(messages, [ordered_set, named_table, public])

您也可以使用private,这意味着只有拥有的进程才能读写。

the documentation

  
      
  • public任何进程都可以读取或写入表格。
  •   
  • protected所有者进程可以读取和写入表。其他进程只能读取表。这是访问权限的默认设置。
  •   
  • private只有所有者进程才能读取或写入表。
  •   

在您的示例中,您在一个进程(调用start_message_channel)中创建表,然后尝试从另一个进程调用ets:insertspawn(?MODULE, channel, [])创建一个新进程,以channel为切入点。

由于您的表格未标记为public,因此来自其他流程的对ets:insert的调用将失败并显示badarg

the documentation, again

  

通常,如果任何参数的格式错误,表标识符无效或者由于表访问权限而拒绝操作,则以下函数将以badarg原因退出(protectedprivate)。

附注:如果您使用named_table,则ets:new 返回的值表名,因此您可以这样做:

-define(TABLE, messages).

% later...
?TABLE = ets:new(?TABLE, [named_table, ordered_set, protected])

...并且您不需要将返回的值存储在状态中。