limp_chimp
limp_chimp

Reputation: 15213

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.

Upvotes: 7

Views: 1606

Answers (2)

rurkss
rurkss

Reputation: 113

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

Upvotes: 1

Dogbert
Dogbert

Reputation: 222398

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.

Upvotes: 8

Related Questions