Skip to content

Latest commit

 

History

History
161 lines (133 loc) · 3.32 KB

concurrency.livemd

File metadata and controls

161 lines (133 loc) · 3.32 KB

Untitled notebook

Section

defmodule Example do
  def add(a, b) do
    IO.puts(a + b)
    a + b
  end
end

# 5
spawn(Example, :add, [3, 2])
current_process = self()
# 40
spawn(fn -> send(current_process, 40) end)
# we are self()
receive do
  40 -> IO.puts("Correct")
  _ -> IO.puts("Wrong answer.")
end
defmodule Bomb do
  def explode, do: exit(:kaboom)
end

# current process not affected
pid = spawn(Bomb, :explode, [])
# does not actually exit because, since its isnt linked to current process,
# current process continues excecuting 
Process.alive?(pid)
# spawn_link(Bomb, :explode, []) #links the spawned process to current process,
# it will cause current process to crash
# so that it doesnt crash self trap the exit flag
Process.flag(:trap_exit, true)
# links the spawned process to current process,
pid2 = spawn_link(Bomb, :explode, [])
Process.alive?(pid2)
defmodule Grenade do
  def explode, do: exit(:kaboom)

  def run do
    # enable us to get updates ot process without linkin to self
    spawn_monitor(Grenade, :explode, [])

    receive do
      {:DOWN, _ref, :process, _from_pid, reason} ->
        IO.puts("EXit reason: #{reason}")
    end
  end
end

Grenade.run()
# Agents => an abstraction to Processes,
# They are a way of maintaining state
{:ok, agent} = Agent.start_link(fn -> 42 end)
Agent.update(agent, fn state -> 5555 end)
Agent.get(agent, & &1) |> IO.puts()
# Agent.start_link, links the process to self()
# Tasks
# Used to call async functions,
# code that retrieves its value later
defmodule Example1 do
  def double(x) do
    :timer.sleep(300)
    x * 2
  end
end

task = Task.async(Example1, :double, [2000])
Task.await(task) |> IO.puts()

# start uses to start a process whose value we dont care about or if the function run for a very long time
{:ok, task1} =
  Task.start(fn ->
    :timer.sleep(2000)
    IO.puts("eee")
  end)

# Task.await(task1)
# Process.
# GenServer
# handle call is synchronous
# handle cast is asynchronous
# handle info used to handle data send to GenServer via send()
defmodule SimpleQueue do
  use GenServer

  @doc """
  GenServer.init/1 callback
  """
  def init(state), do: {:ok, state}

  @doc """
  GenServer.handle_call/3 callback
  """
  def handle_call(:dequeue, _from, [value | state]) do
    {:reply, value, state}
  end

  def handle_call(:dequeue, _from, []), do: {:reply, nil, []}

  def handle_call(:queue, _from, state), do: {:reply, state, state}

  @doc """
  GenServer.handle_cast/2 callback
  """
  def handle_cast({:enqueue, value}, state) do
    {:noreply, state ++ [value]}
  end

  ### Client API/ Helper functions

  @doc """
  Start our queue and link it.
  This is a helper function
  """
  def start_link(state \\ []) do
    GenServer.start(__MODULE__, state, name: __MODULE__)
  end

  def enqueue(value), do: GenServer.cast(__MODULE__, {:enqueue, value})
  def queue, do: GenServer.call(__MODULE__, :queue)
  def dequeue, do: GenServer.call(__MODULE__, :dequeue)
end
# Process.flag(:trap_exit, false)
SimpleQueue.start_link([1, 2, 3, 4])
SimpleQueue.dequeue() |> IO.puts()
SimpleQueue.dequeue() |> IO.puts()
SimpleQueue.queue()
SimpleQueue.enqueue(2)
SimpleQueue.enqueue(2)
# use GenServer.stop(SimpleQueue) to stop the server

# SimpleQueue.dequeue() |> IO.puts()