Concurrency Erlang ETS插入/2错误

Concurrency Erlang ETS插入/2错误,concurrency,erlang,erlang-shell,ets,Concurrency,Erlang,Erlang Shell,Ets,我试图创建一个简单的Erlang进程,并访问ETS模块 我的源代码包括: 进程创建: start_message_channel() -> Table = ets:new(messages, [ordered_set, named_table]), Channel = spawn(?MODULE, channel, []), {Channel, {table, Table}}. 过程逻辑: channel() -> receive

我试图创建一个简单的Erlang进程,并访问ETS模块

我的源代码包括:

  • 进程创建:

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

    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.
    
  • 与流程的沟通

    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}]}]}
    
    1>cd(“C:/Users/dauma”)。
    C:/Users/dauma
    好啊
    2> c(信息通道)。
    {好的,消息通道}
    3> 对象=消息\通道:启动\消息\通道()。
    {,{表,消息}
    4> 消息通道:将消息发送到消息通道(对象“Hello World!”)。
    =错误报告===2016年5月19日::11:09:27===
    使用退出值处理时出错:
    {badarg,[{ets,insert,[messages,“Hello World!”],[]},
    {消息通道,通道,0,
    [{file,“message_channel.erl”},{line,35}]}
    

    有人能告诉我,问题出在哪里吗?

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

    如果要从其他进程读写,请使用
    public

    Table = ets:new(messages, [ordered_set, named_table, public])
    
    您还可以使用
    private
    ,这意味着只有拥有的进程才能读写

    Per:

    • public
      任何进程都可以读取或写入表
    • protected
      所有者进程可以读取和写入表。其他进程只能读取该表。这是访问权限的默认设置
    • private
      只有所有者进程可以读取或写入表
    在您的示例中,您在一个进程中创建表(调用
    start\u message\u channel
    ),然后尝试从另一个进程调用
    ets:insert
    spawn(?MODULE,channel,[])
    创建一个新进程,以
    channel
    作为其入口点

    由于您的表未标记为
    public
    ,因此从另一个进程调用
    ets:insert
    失败,返回
    badarg

    Per:

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


    旁注:如果使用
    named_table
    ,则从
    ets:new
    返回的值是表名,因此可以执行以下操作:

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

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

    谢谢您的回答!在你建议的小改动之后,一切都很有魅力!为了更好地理解,您能告诉我,在我的示例中,创建表更新它的不是同一个进程吗?您可以在#1中创建表,然后生成一个进程来运行channel/0。这是执行插入的过程,因此私有是不起作用的。是的,但默认值是
    受保护的
    @rvirding,true(我永远记不起来了,所以我倾向于显式);更新了我的答案。