【问题标题】:Erlang ETS insert/2 errorErlang ETS 插入/2 错误
【发布时间】:2016-09-16 00:20:13
【问题描述】:

我正在尝试创建一个可以访问 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}]}]}

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

【问题讨论】:

    标签: concurrency erlang erlang-shell ets


    【解决方案1】:

    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

    一般来说,如果任何参数格式错误、表标识符无效或由于表访问权限(protectedprivate )。


    旁注:如果你使用named_table,从ets:new返回的值表名,所以你可以这样做:

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

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

    【讨论】:

    • 感谢您的回答!在您建议的小改动之后,一切都像魅力一样!为了更好地理解,你能告诉我,在我的例子中,创建表的过程不是更新它吗?
    • 您在#1 中创建表,然后生成一个进程来运行通道/0。这就是插入的过程,因此私有化不起作用。
    • 是的,但默认是protected
    • @rvirding, true(我不记得了,所以我倾向于直言不讳);更新了我的答案。
    猜你喜欢
    • 2016-09-10
    • 2010-12-30
    • 2016-10-23
    • 2016-10-27
    • 2016-06-03
    • 2012-10-14
    • 2016-07-09
    • 2018-09-25
    • 2012-08-07
    相关资源
    最近更新 更多