Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to send a message to all child processes in elixir/erlang?

Let's imagine that I'm spawning multiple child processes in elixir.

defmodule Child do
  def start(name) do
    receive do
      msg -> IO.puts "Message received by #{name}: #{inspect msg}"
    end
  end
end

defmodule Parent do
  def main do
    child1 = spawn_link (fn -> Child.start("1") end)
    child2 = spawn_link (fn -> Child.start("2") end)
    child3 = spawn_link (fn -> Child.start("3") end)
  end
end

Is there anyway that I can send a message to all of the children of my current process (or some other process)?

send_to_children self(), "hello to all children"

As in, some way that I can tell the runtime to broadcast a message to all of processes linked to a current process? I could of course store all of the spawned pids in a data structure of some kind and loop over it to do this, but if there is some kind of canonical way to do this it seems like it would be more efficient and less error prone.

like image 409
limp_chimp Avatar asked Jan 24 '18 07:01

limp_chimp


2 Answers

Since you're using spawn_link, you can fetch list of all linked processes and send a message to them:

defmodule Child do
  def start(name) do
    receive do
      msg -> IO.puts "Message received by #{name}: #{inspect msg}"
    end
  end
end

defmodule Parent do
  def main do
    child1 = spawn_link (fn -> Child.start("1") end)
    child2 = spawn_link (fn -> Child.start("2") end)
    child3 = spawn_link (fn -> Child.start("3") end)
    {:links, links} = Process.info(self, :links)
    for pid <- links do
      send pid, :foo
    end
  end
end

Parent.main
:timer.sleep(1000)

Output:

Message received by 2: :foo
Message received by 1: :foo
Message received by 3: :foo

I don't think it's possible to get a list of child processes of a process directly: http://erlang.org/pipermail/erlang-questions/2013-April/073125.html. There are ways if you spawn them from a Supervisor but not for arbitrary cases.

like image 94
Dogbert Avatar answered Sep 22 '22 18:09

Dogbert


did you look at PubSub? The only restriction is that all your processes will be named the same https://hexdocs.pm/elixir/master/Registry.html#module-using-as-a-pubsub

{:ok, _} = Registry.start_link(:duplicate, Registry.PubSubTest)

# process 1
{:ok, _} = Registry.register(Registry.PubSubTest, "room_1", [])

# process 2
{:ok, _} = Registry.regiser(Registry.PubSubTest, "room_1", [])

Registry.dispatch(Registry.PubSubTest, "room_1", fn entries ->
 for {pid, _} <- entries, do: send(pid, {:broadcast, "world"})
end)
#=> :ok
like image 31
rurkss Avatar answered Sep 22 '22 18:09

rurkss