15 Jul 2013, 03:42
Dave_gnome_head_isolated_pragsmall

Dave Thomas (337 posts)

  • Alter the code so that successive ticks are sent to each registered client (so the first goes to the first client, the second the next client, and so on). Once the last client receives a tick, it starts back at the first. The solution should deal with new clients being added at any time.
08 Jan 2014, 07:23
Generic-user-small

Eric Liaw (3 posts)

Don’t really like the default definition of generator when the inputs are empty, but seemed to cause the least amount of duplicate code. Also, I don’t like that I used the if inside the main generator method, wasn’t sure a clean way around it though.

defmodule Tick do
  @interval 2000 # 2 seconds
  
  @name :ticker
  
  def start do
    pid = spawn(__MODULE__, :generator, [[]])
    :global.register_name(@name, pid)
  end
  
  def register(client_pid) do
    :global.whereis_name(@name) <- { :register, client_pid }
  end
  
  def generator(clients) do
    generator(clients, [], nil)
  end
  
  def generator([], [], nil) do
    receive do
      { :register, pid } ->
        IO.puts "registering #{inspect pid}"
        generator([pid], [], pid)
    after
      @interval ->
        IO.puts "tick"
        generator([], [], nil)
    end
  end
  
  def generator(active_clients, pending_clients, first_client) do
    receive do
      { :register, pid } ->
        IO.puts "registering #{inspect pid}"
        generator(active_clients, pending_clients ++ [pid], first_client)
    after
      @interval ->
        IO.puts "tick"
        [next_client | remaining_clients] = active_clients
        next_client <- {:tick}
        if next_client == first_client do
          generator(remaining_clients ++ pending_clients ++ [next_client], [], first_client)
        else
          generator(remaining_clients ++ [next_client], pending_clients, first_client)
        end
    end
  end
end

defmodule Client do
  def start do
    pid = spawn(__MODULE__, :receiver, [])
    Tick.register(pid)
  end

  def receiver do
    receive do
      { :tick } ->
        IO.puts "tock in client"
        receiver
    end
  end
end
06 Mar 2014, 00:32
Webcam_pragsmall

Andrea Bernardo Ciddio (2 posts)

What about a helper notify function:

defmodule CycleTick do
  @interval 2000
  @name :ticker

  def start do
    pid = spawn __MODULE__, :generator, [[], []]
    :global.register_name @name, pid
  end

  def register(client_pid) do
    send :global.whereis_name(@name), { :register, client_pid }
  end

  def generator(clients, waiting_clients) do
    receive do
      { :register, pid } ->
        IO.puts "registering #{inspect pid}"
        generator [pid | clients], waiting_clients
      after @interval ->
        IO.puts "tick"
        waiting_clients = notify(clients, waiting_clients)
        generator(clients, waiting_clients)
    end
  end

  def notify([], []), do: []
  def notify(clients, []), do: notify(clients, clients)

  def notify(_clients, [next_client | waiting_clients]) do
    send next_client, { :tick }
    waiting_clients
  end

end

defmodule Client do
  def start do
    pid = spawn __MODULE__, :receiver, []
    CycleTick.register pid
  end

  def receiver do
    receive do
      { :tick } ->
        IO.puts "tock in client"
        receiver
    end
  end
end
  You must be logged in to comment