2017-04-10 7 views
1

私は現在、エリクシルのユビキタスプロセスリングを使っています。 リングがリンクされているが、以下の方法で:プロセスリングの非対称性のリンク

iex(1)> Ring.Worker.create_ring_of_linked_processes(3) 
Ring.Worker.create_ring_of_linked_processes(3) 
[%{"links" => [#PID<0.121.0>, #PID<0.120.0>], "pid" => #PID<0.122.0>}, 
%{"links" => [#PID<0.120.0>, #PID<0.122.0>], "pid" => #PID<0.121.0>}, 
%{"links" => [#PID<0.121.0>], "pid" => #PID<0.120.0>}] 

私はここのリンクの非対称性を気づいた - #PID<0.120.0>マッピング"links" => [#PID<0.121.0>,#PID<0.122.0>]だけでなく"links" => [#PID<0.121.0>]を持っている必要がありますか?あなたはその:linksを集めると同時にプロセスをリンクしているので、これがある

def loop() do 
    receive do 
     {:link, pid} when is_pid(pid) -> 
     Process.link(pid) 
     loop() 
    end 
    end 

    def create_ring_of_linked_processes(num_of_processes) do 
    num_of_processes 
    |> create_processes 
    |> link_processes([]) 
    end 


    def link_processes([pid1, pid2 | rest], linked_processes) do 
    send(pid1, {:link, pid2}) 
    :timer.sleep(1) 
    {:links, links} = Process.info(pid1, :links) 
    link_processes(
     [pid2 | rest], [%{"pid" => pid1, "links" => links} | linked_processes] 
    ) 
    end 

    def link_processes([pid | []], linked_processes) do 
    %{"pid" => first_pid, "links" => _} = List.last(linked_processes) 
    send(pid, {:link, first_pid}) 
    :timer.sleep(1) 
    {:links, links} = Process.info(pid, :links) 
    [%{"pid" => pid, "links" => links} | linked_processes] 
    end 

    @spec create_processes(integer) :: [pid] 
    def create_processes(num_of_processes) do 
    for _ <- 1..num_of_processes, do: spawn(__MODULE__, :loop, []) 
    end 
+1

[MCVE](https://stackoverflow.com/help/mcve)を投稿できますか?あなたが 'Process.info(pid、:links)'からのリンクを取得しているなら、あなたはそれをあまりにも早く呼び出すかもしれません。プロセスが 'Process.link/1'を使用してリンクされている場合、リンクは対称でなければなりません。 – Dogbert

+0

@Dogbert確かに更新されました。私は1ミリ秒の遅延を使用しています。 – category

+2

すべての 'Process.link/1'呼び出しが行われた後、' Process.info(_、:links) 'を収集するためにこれを変更する必要があると思います。 – Dogbert

答えて

2

が、そのプロセスのためのいくつかのリンクは、あなたがその収集後に作成されている次のように

コードがありますリンク。

たとえば、プロセスaを生成してリンクを収集すると、空のリストになります。

iex(1)> a = spawn(fn -> :timer.sleep(:infinity) end) 
#PID<0.82.0> 
iex(2)> Process.info(a, :links) 
{:links, []} 

あなたが今bを起動し、aにリンクした場合、bは、そのリンクで[a]を持つことになりますし、a[b]を持つことになります。

iex(3)> b = spawn(fn -> Process.link(a); :timer.sleep(:infinity) end) 
#PID<0.85.0> 
iex(4)> Process.info(b, :links) 
{:links, [#PID<0.82.0>]} 
iex(5)> Process.info(a, :links) 
{:links, [#PID<0.85.0>]} 

したがって、各プロセスの最終リンクを希望する場合は、すべてのリンクが完了した後に各プロセスのリンクを収集する必要があります。

+0

'link_processes/2'関数が' create_ring_of_linked_processes/1'関数で実行された後、 'Process.info(_、:links)'を使ってリンクをチェックすることで、対称リンクが報告されるようになりましたが、このリンクが完結していることを確認してください - これをエリキシルで知る方法はありますか? 'send(pid、{:link、_})'が実行されても、 'loop/0'プロセスは未知の時間内にメッセージを受信して​​処理する必要があります。 – category

+1

あなたはそうです、それは保証されていません。これが行われる通常の方法は、リンクが完了した後に受信者が別のメッセージを発信者に送り返すことです。発信者は、処理を進める前にメッセージが到着するまで待つ必要があります。 'GenServer.call'は私が今説明したものと非常によく似た何かの堅牢な実装です。実際のアプリケーションでこれを使うつもりならば、プロセスを 'GenServer'に変えたいかもしれません。 – Dogbert

+0

リンクの対称性を保証していない単なる例だったので、答えとしてマークしていただきありがとうございます。 – category

関連する問題