Created
September 11, 2021 15:16
-
-
Save wrgoldstein/a0c18f89f9b540880f35065f84b7e56d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| defmodule Exstuf do | |
| @doc """ | |
| Illustration of the philosopher dining problem. | |
| Reimplementation of https://www.golangprograms.com/go-language/concurrency.html | |
| ## Examples | |
| iex> Exstuf.start() | |
| for _ <- 1..5, do: :satisfied | |
| """ | |
| def start do | |
| eaters = [:Mark, :Russell, :Rocky, :Haris, :Root] | |
| forks = [:one, :two, :three, :four, :five] | |
| places = assign_forks(eaters, forks) | |
| # Starts a supervised mutex process | |
| {:ok, _pid} = Supervisor.start_link([{Mutex, name: Fork}], strategy: :one_for_one) | |
| tasks_with_results = | |
| Enum.map(eaters, fn eater -> Task.async(fn -> eat(eater, places) end) end) | |
| |> Task.yield_many() | |
| results = | |
| Enum.map(tasks_with_results, fn {task, res} -> | |
| # Shut down the tasks that did not reply nor exit | |
| res || Task.shutdown(task, :brutal_kill) | |
| end) | |
| for {:ok, res} <- results, do: res | |
| end | |
| @doc "Each eater shares a fork on each side with their neighbor" | |
| def assign_forks(eaters, forks) do | |
| for {p, i} <- Enum.with_index(eaters), do: {p, {Enum.at(forks, i), Enum.at(forks, i - 1)}} | |
| end | |
| @doc "Simulate time spent eating" | |
| def sleep_for_eating do | |
| :timer.sleep(:rand.uniform(500)) | |
| end | |
| @doc "Simulate time spent thinking" | |
| def sleep_for_thinking do | |
| :timer.sleep(:rand.uniform(500)) | |
| end | |
| def eat(eater, places) do | |
| # Number of times a philosopher eats | |
| hunger = 3 | |
| IO.puts("#{eater} sits down!") | |
| {fork1, fork2} = places[eater] | |
| Enum.each(0..hunger, fn _ -> | |
| IO.puts("#{eater} is hungry!") | |
| lock = Mutex.await_all(Fork, [fork1, fork2]) | |
| IO.puts("#{eater} is eating!") | |
| sleep_for_eating() | |
| IO.puts("#{eater} done eating, time to think!") | |
| Mutex.release(Fork, lock) | |
| sleep_for_thinking() | |
| end) | |
| :satisfied | |
| end | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment