4

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

どこに問題があるのでしょうか。

4

1 に答える 1

11

ETS テーブルは Erlang プロセスによって所有され、アクセス制御があります。デフォルトでは、テーブルはprotectedそれを所有するプロセスによってのみ書き込まれ、他のプロセスから読み取ることはできます。

別のプロセスから読み書きする場合は、 を使用しますpublic

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

を使用することもできますprivate。つまり、所有しているプロセスだけが読み書きできます。

ドキュメントごと:

  • publicどのプロセスも、テーブルに対して読み取りまたは書き込みを行うことができます。
  • protected所有者プロセスは、テーブルの読み取りと書き込みができます。他のプロセスはテーブルを読み取ることしかできません。これは、アクセス権のデフォルト設定です。
  • private所有者プロセスのみがテーブルの読み取りまたは書き込みを行うことができます。

あなたの例では、1 つのプロセス (を呼び出すプロセス) でテーブルを作成し、別のプロセスからstart_message_channel呼び出しようとします: をエントリ ポイントとして新しいプロセスを作成します。ets:insertspawn(?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])

...そして、返された値を状態に保存する必要はありません。

于 2016-05-19T09:12:08.727 に答える