2017-04-10 3 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을 생성하고 링크를 수집하면 빈 목록이됩니다. 지금 b를 생성하고 a에 연결하면

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

, 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

'create_ring_of_linked_processes/1' 함수에서'link_processes/2' 함수가 실행 된 후에'Process.info (_, : links)'를 사용하여 링크를 검사하여 대칭 링크를보고했습니다. 그러나 나는 생각하지 않습니다 이 '연계가 완료되었습니다'라는 _guarantees_ - 연금술에서 이것을 알 수있는 방법이 있습니까? 'send (pid, {: link, _})'가 실행 되더라도 'loop/0' 프로세스는 여전히 알 수없는 시간 내에 메시지를 수신하고 처리해야합니다. – category

+1

당신 말이 맞습니다. 보장 할 수는 없습니다. 이것이 이루어지는 일반적인 방법은 연결이 완료된 후에 수신자가 호출자에게 다시 다른 메시지를 보내 게하는 것입니다. 발신자는 진행하기 전에 메시지 도착을 기다려야합니다. 'GenServer.call'은 제가 지금 막 설명한 것과 매우 유사한 무언가의 강력한 구현물입니다; 실제 응용 프로그램에서 이것을 사용할 계획이라면 프로세스를'GenServer'로 바꾸는 것이 좋습니다. – Dogbert

+0

대단히 감사합니다. 대칭을 보장하는 링크보고 기능이없는 예제 였기 때문에 대답으로 표시 할 수 있습니다. – category