ここでErlangに行きます。
基本的なレベルでは、2つのオプションが利用可能です。特定のプロセスの動作を変更するためだけに使用したい場合become
(セクション2.1.3のリストのポイント2を参照)、別の再帰関数を使用して次のループを呼び出すだけです。
loop(State) ->
receive
{normal, Msg} -> loop(State);
{change, NewLoop} -> NewLoop(State)
end.
NewLoop
高階関数であると仮定すると、{change, NewLoop}
最初に関数を実行しているプロセスにメッセージを送信するたびに、その定義としてloop/1
使用されます。NewLoop
2番目のオプションは、プロセスをプロキシとして機能させる(および動作を変更する)オプションです。これは、マルセロカントスが提案したものと似ています。プロセスループを作成し、メッセージを新しいメッセージに転送する(コードを盗む)だけです。
become(Pid) ->
receive
Msg -> Pid ! Msg
end,
become(Pid).
理論的には、これは論文が求めることを行います。ただし、実際には、実際のErlangシステムで2番目のオプションを使用することにはリスクがあります。2つのプロセス間の通信では、メッセージに送信者のプロセスIDを「スタンプ」し、応答に受信者のプロセスIDをタグ付けすることがよくある概念です。次のメッセージの交換を行うことができます(これはコードではなく、単なる手書き表記です)。
A = <0.42.0> <-- process identifier
B = <0.54.0>,
A: {A, "hello"},
B: {B, "hi"},
A: {A, "how are you?"}.
B: {B, "Fine!"}.
したがって、A
からのメッセージを期待する場合は、B
などのパターンを使用することで、これらにのみ一致させることができ{B, Message}
ます。転送されたメッセージの場合、このアドレス指定スキームは無効になり、単に壊れます。
別の方法は、参照(make_ref()
)をアドレス指定スキームとして使用して、返されるPidの上にあるメッセージを照合することです。これにより、2つの異なるエンティティを使用して、アドレスと識別子としてのPidの使用が分離されます。
アドレス指定が安全であっても、別の問題があります。プロセスの依存関係です。名前付きプロセス、クラッシュプロセス、モニターなどはどうなりますか?クライアントプロセスには、通知なしに何も問題がないことを確認するために、モニター、リンクなどがすべて設定されている場合があります。ルーティングプロセスを変更して出口信号をトラップして転送することにより、物事をより安全にすることができるはずです。
loop(State) ->
receive
{normal, Msg} -> loop(State);
{become, Pid} ->
process_flag(trap_exit, true), % catch exit signals as messages
link(Pid), % make it so if one process crashes, the other receives the signal
become(Pid)
end.
become(Pid) ->
receive
{'EXIT', Pid, killed} -> exit(self(), kill); %% uncatchable termination
{'EXIT', Pid, normal} -> ok; %% die normally too
{'EXIT', Pid, Reason} -> exit(Reason); %% die for the same reason as Pid
Msg -> Pid ! Msg %% forward the message
end,
become(Pid).
Pid
このテストされたコードは、最初のプロセスに依存するプロセスがで表されるものと同じエラーメッセージを受け取りbecome(Pid)
、ルーティングをかなり透過的にするため、より安全であるはずです。ただし、これが実際のアプリケーションで長期的に機能することを保証するものではありません。
のようなことを表現して実行することは可能であり、概念的には十分に単純ですがbecome
、Erlangの標準ライブラリは、2番目のユースケースを念頭に置いて実際には考えられていませんでした。実際のアプリケーションでは、現在存在するすべてのErlangアプリケーションで広く使用されている最初の方法のみをお勧めします。2つ目はまれであり、問題を引き起こす可能性があります
*become/1
*最後の例での関数の呼び出し?MODULE:become(Pid)
は、将来のホットコードの読み込みに関連する潜在的なクラッシュを回避するためのものである可能性があります。*