2017-11-03 10 views
0

モジュールに変数があり、変数値を更新する受信メソッドがあります。複数のプロセスが同時にこのメソッドを呼び出しています。 1つのプロセスがそれを変更しているときにこの変数をロックする必要があります。 Erlangの異なるプロセス間で変数をロックする方法はありますか

以下mytest.erl

%%%------------------------------------------------------------------- 
-module(mytest). 

%% API 
-export([start_link/0,display/1,callDisplay/2]). 

start_link()-> 
    Pid=spawn(mytest,display,["Hello"]), 
    Pid. 

display(Val) -> 
    io:format("It started: ~p",[Val]), 
    NextVal= 
    receive 
     {call,Msg}-> 
     NewVal=Val++" "++Msg++" ", 
     NewVal; 
     stop-> 
     true 
    end, 
    display(NextVal). 

callDisplay(Pid,Val)-> 
    Pid!{call,Val}. 
としてサンプルはそれを

Pid=mytest:start_link(). 

2つのプロセスを開始します

私はそれが "ウォルター" を追加することを願って

同じ時間に
P1=spawn(mytest,callDisplay,[Pid,"Walter"]), 
P2=spawn(mytest,callDisplay,[Pid,"Dave"]). 

それを呼んでいます、 "Dave"、 "Hello Walter Dave"のようなものがありますが、一緒に走っている人が多すぎる場合、いくつかの名前(Walter、Dave、e tc)が上書きされます。

P1、P2が同じ時刻に開始したとき、Valは両方とも「Hello」です。 P1は "Walter"を "Hello Walter"に追加し、P2は "Dave"を追加して "Hello Dave"になります。 P1は最初にNextValに "Hello Walter"として保存し、P2はそれをNextValに "Hello Dave"として保存したので、結果は "Hello Dave"になります。 「Hello Walter」は「Hello Dave」に置き換えられ、「Walter」は永遠に失われます。

「Val」をロックする方法はありますか?「Walter」を追加すると、「Dave」は値の設定が完了するまで待機しますか?

+5

display/1コールのためdisplay/1パラメータです。メッセージは同時に処理されるのではなく、順次処理されます。これは起こってはならない。この現象を再現するための完全なコードを投稿できますか? – Dogbert

+0

クライアントに問題がある可能性があります。 'callDisplay'プロセスのどれかがタイムアウトなどのエラーを出しますか? –

答えて

3

これは古い質問ですが、説明する価値はあります。あなたが言ったと私は正しいんだ場合、 あなたは

「こんにちはウォルター」、および「こんにちはデイブ」を見ることを期待しています。何から ただし、連続した名前が、前者に追加され、「こんにちはウォルター・デイブ..」

をこの動作は正常であり、それはErlangのメモリモデルで簡単に見てみましょう見るために見ています。

プロセス制御ブロック(PCB): このことのキュー内のメッセージにプロセスpid、登録名、テーブル、州とのポインタを保持するErlangのプロセスメモリは、3つの主要部分に分かれています。

スタック: このホールド機能のパラメータ、ローカル変数、およびファンクションリターンアドレス。

プライベートヒープ:タプル、リスト、バイナリ(64バイト以下)などの着信メッセージ複合データを保持します。

これらのメモリ内のすべてのデータは、所有プロセスに属し、所有プロセスに属します。

ステージ1:Pid=spawn(mytest,display,["Hello"])が呼び出されると

、サーバ・プロセスが作成され、その後、「こんにちは」と表示関数は、引数が呼び出されると渡さ。サーブ・プロセスでdisplay/1が実行されるため、"Hello"引数はサーバーのプロセス・スタックに存在します。display/1の実行は、receive節に達するまで続き、ブロックして、フォーマットに一致するメッセージを待ちます。

ステージ2:

P1はそれがServerPid ! {call, "Walter"}を実行し、開始し、その後、P2ServerPid ! {call, "Dave"}を実行します。どちらの場合も、erlangはメッセージのコピーを作成し、サーバのプロセスメールボックスに送信します(プライベートヒープ)。このメールボックスのコピーされたメッセージは、クライアントのものではなくサーバープロセスに属します。 {call, "Walter"}と一致すると、Msg"Walter"にバインドされます。 段1から、に限定され、Newvalは、に結合することがわかっている。

この時点では、P2のメッセージ、{call, "Dave"}は、display/1隣の再帰呼び出しに起こるのだろう次のreceive句を待っているサーバーのメールボックスに残っています。 NextValNewValにバインドされ、への再帰呼び出しが"Hello Walter"が引数として渡されます。これにより、最初のプリント"Hello Walter "がサーバーのプロセススタックにも存在するようになりました。

receive句が再び届くと、P2のメッセージ{call, "Dave"}が一致します。 NewValNextVal"Hello Walter" ++ " " ++ "Dave" = "Hello Walter Dave".にバインドされます。これはValとしてHello Walter Daveという新しいものとしてdisplay/1への引数として渡されます。要するに、この変数はすべてのサーバーループで更新されます。 gen_serverの動作では、Stateという用語と同じ目的を果たします。あなたのケースでは、連続するクライアント呼び出しは、メッセージをこのサーブ状態変数に追加するだけです。今、あなたの質問に、

は私がValをロックすることができます方法はあり、私たちは"Walter"を追加するときに、値の設定まで待っ"Dave"意志が行われていますか?

いいえロックしないでください。 Erlangはこのように動作しません。
プロセスロック構造は必要ありません。 データ(変数)は、それを作成したプロセスに常に変更されずにプライベートです(は共有ヒープの大きなバイナリを除きます)。 また、受領プロセスによって処理されているのは、Pid ! Msg構成で実際に使用したメッセージではありません。それはコピーです。 display/1のパラメータは、サーバプロセス自身によって作成されたもので、display/1のすべての呼び出しが行われるたびに、スタックというメモリに格納されているため、サーバープロセスに属します。したがって、他のプロセスがその変数を見ることさえできない方法はありません。

はい。順次メッセージ処理による処理 これは、サーバープロセスが実行している処理とまったく同じです。 1つのメッセージをキューからポーリングします。 {call, "Walter"}が撮影されたときには、{call, "Dave"}がキュー内で待機していました。あなたは、サーバーの状態を変更するので、あなたが予想外のあいさつを参照してください理由は、プロセスが一度に一つのメッセージを処理できるプロセス{call, "Dave"}

関連する問題