我正在尝试创建一个简单的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}]}]}
有人能告诉我,哪里可能有问题吗?
ETS表由Erlang进程所有,并具有访问控制。默认情况下,该表为protected
,只能由拥有它的进程写入,但也可以从其他进程读取。
如果要从不同的进程进行读写,请使用public
。
Table = ets:new(messages, [ordered_set, named_table, public])
您还可以使用private
,这意味着只有拥有进程才能进行读写。
根据文件:
public
任何进程都可以读取或写入该表protected
所有者进程可以对表进行读写操作。其他进程只能读取该表。这是访问权限的默认设置private
只有所有者进程才能读取或写入该表
在您的示例中,您在一个进程(调用start_message_channel
的进程)中创建表,然后尝试从另一个进程调用ets:insert
:spawn(?MODULE, channel, [])
创建一个新进程,channel
作为其入口点。
因为您的表未标记为public
,所以其他进程对ets:insert
的调用将以badarg
失败。
根据文件,再次:
通常,如果任何参数的格式错误、表标识符无效或由于表访问权限(
protected
或private
)而拒绝操作,则以下函数将退出,原因为badarg
。
附带说明:如果使用named_table
,则从ets:new
返回的值是表名,因此可以执行以下操作:
-define(TABLE, messages).
% later...
?TABLE = ets:new(?TABLE, [named_table, ordered_set, protected])
并且您不需要将返回的值存储在state中。