Erlang ETS insert/2 错误

Erlang ETS insert/2 error

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

我的源代码包括:

  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.
    

在 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}]}]}

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

ETS tables 由 Erlang 进程拥有,并具有访问控制。默认情况下 table 是 protected 并且只能由拥有它的进程写入,尽管它可以从其他进程读取。

如果要从不同的进程读取和写入,请使用 public

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

也可以使用private,即只有所属进程可以读写

根据 the documentation:

  • public Any process may read or write to the table.
  • protected The owner process can read and write to the table. Other processes can only read the table. This is the default setting for the access rights.
  • private Only the owner process can read or write to the table.

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

因为您的 table 没有被标记为 public,所以从其他进程调用 ets:insert 失败并返回 badarg

根据 the documentation, again:

In general, the functions below will exit with reason badarg if any argument is of the wrong format, if the table identifier is invalid or if the operation is denied due to table access rights (protected or private).


旁注:如果您使用 named_table,从 ets:new 返回的值是 table 名称,因此您可以这样做:

-define(TABLE, messages).

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

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