Dau*_*kas 3 concurrency erlang ets erlang-shell
我试图通过访问ETS模块创建一个简单的Erlang进程.
我的源代码包括:
流程创建:
start_message_channel() ->
Table = ets:new(messages, [ordered_set, named_table]),
Channel = spawn(?MODULE, channel, []),
{Channel, {table, Table}}.
Run Code Online (Sandbox Code Playgroud)流程逻辑:
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.
Run Code Online (Sandbox Code Playgroud)与流程沟通
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.
Run Code Online (Sandbox Code Playgroud)在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}]}]}
Run Code Online (Sandbox Code Playgroud)
谁能告诉我,问题可能出在哪里?
ETS表由Erlang进程拥有,并具有访问控制.默认情况下,该表是protected并且只能由拥有它的进程写入,尽管可以从其他进程读取.
如果要从其他进程读取和写入,请使用public.
Table = ets:new(messages, [ordered_set, named_table, public])
Run Code Online (Sandbox Code Playgroud)
您也可以使用private,这意味着只有拥有进程才能读写.
根据文件:
public任何进程都可以读取或写入表.protected所有者进程可以读取和写入表.其他进程只能读取表.这是访问权限的默认设置.private只有所有者进程才能读取或写入表.
在您的示例中,您在一个进程(一个调用start_message_channel)中创建表,然后您尝试ets:insert从另一个进程调用:spawn(?MODULE, channel, [])创建一个新进程,channel并将其作为入口点.
由于您的表未标记为public,因此ets:insert来自其他进程的调用失败badarg.
根据文档,再次:
通常,
badarg如果任何参数的格式错误,表标识符无效或者由于表访问权限(protected或private)而拒绝操作,则下面的函数将退出.
附注:如果使用named_table,返回的值ets:new 是表名,因此您可以这样做:
-define(TABLE, messages).
% later...
?TABLE = ets:new(?TABLE, [named_table, ordered_set, protected])
Run Code Online (Sandbox Code Playgroud)
...而且您不需要将返回的值存储在状态中.