7

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.

limp_chimp
  • 13,475
  • 17
  • 66
  • 105

2 Answers2

8

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.

Dogbert
  • 212,659
  • 41
  • 396
  • 397
  • 5
    The issue with this approach is that links are bidirectional. So if you start Child under a supervisor, then the supervisor, which is the parent, will also be in the list and receive messages. It is always best to store the names of the PIDs you want to talk to or put them under a supervisor and use the Supervisor API. – José Valim Jan 24 '18 at 08:23
  • Both responses are super helpful. I didn't know about Supervisors either -- just a beginner! – limp_chimp Jan 24 '18 at 16:36
1

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
rurkss
  • 113
  • 1
  • 4