Skip to content

Instantly share code, notes, and snippets.

@AndriSig
Created April 21, 2016 19:49
Show Gist options
  • Save AndriSig/7b06ab429cd0023893610ba153f8b901 to your computer and use it in GitHub Desktop.
Save AndriSig/7b06ab429cd0023893610ba153f8b901 to your computer and use it in GitHub Desktop.
-module(sushi).
-export([main/1, run/3]).
%% K is the number of chairs, N is the number of customers.
%% Initializes the threads and waits for it to finish
main([K, N, SleepTime|_]) ->
init(list_to_integer(K)),
gen_customers(list_to_integer(N), list_to_integer(SleepTime)),
loop(0, list_to_integer(N)),
unregister(main),
unregister(cpid).
run(K,N,SleepTime) ->
main([integer_to_list(K),integer_to_list(N),integer_to_list(SleepTime)]).
%% Takes in the number of seats and spawns the controller along with registering it and the main
init(K) when is_integer(K) ->
register(cpid, spawn(fun() -> seats(K) end)),
register(main, self()).
%% Generates N customer threads into the bar
gen_customers(0,_) -> ok;
gen_customers(N,SleepTime) when is_integer(N) ->
spawn(fun() -> bar(SleepTime) end),
gen_customers(N-1,SleepTime).
%% Waits for all the customer threads to finish
loop(N, N) -> cpid!stop;
loop(M, N) ->
receive
{_, left} ->
io:format("~p customers left~n", [N-M]),
loop(M + 1, N)
end.
%% Takes in the number of seats and launches the proper controller
seats(K) ->
io:format("seats: K ~p B ~p ~n", [K ,0]),
seats(K, 0, 0, []).
%% K is the number of seats, Waiting the number waiting for seats,
%% sitting the number eating, and L a Queue of Pids
seats(K, Waiting, Sitting, L) ->
%% If there are people waiting they get served first
if
Waiting > 0, Sitting == K - 1 ->
hd(L) ! {cpid, sit_down},
io:format("Customer ~p has sat down~n", [hd(L)]),
group_seats(K, Waiting - 1, Sitting + 1, tl(L));
Waiting > 0, Sitting < K - 1 ->
hd(L) ! {cpid, sit_down},
io:format("Customer ~p has sat down~n", [hd(L)]),
seats(K, Waiting - 1, Sitting + 1, tl(L));
Sitting > K -> % this should never happen
throw("too many ppl");
true ->
%% If noone is waiting we wait for people to arrive or finish eating
receive
%% Message received from a customer to announce that he is waiting
{Pid, eat} ->
io:format("Customer ~p has arrived~n", [Pid]),
Pid ! {cpid, sit_down},
io:format("Customer ~p has sat down~n", [Pid]),
if
%% If K customers have arrived we branch into a function to handle that behavior
Sitting == K - 1 ->
group_seats(K, Waiting, Sitting + 1, L );
%% Else we just let the customers take a seat
true ->
seats(K, Waiting, Sitting + 1, L)
end;
%% Message recieved from a customer to announce that he is done eating
{Pid, done} ->
if
%% If there is noone sitting there is an error, should never happen
Sitting == 0 ->
{cpid, invalid_finish, Pid};
%% If someone is waiting we let him sit.. Now that i think about it
%% this is entirely pointless because of the group mechanic
%% Waiting > 0 -> hd(L) ! {cpid, sit_down},
%% seats(K, Waiting - 1, Sitting, tl(L));
%% Someone stands up and leaves.
true ->
io:format("Customer ~p has finished eating~n",[Pid]),
seats(K, Waiting, Sitting - 1, L)
end;
stop ->
ok
end
end.
%% A function that branches of seats in order to make sure that once all seats fill up noone else eats until
%% they empty up entirely
group_seats(K, Waiting, 0, L) -> seats(K, Waiting, 0, L);
group_seats(K, Waiting, Sitting, L) ->
%io:format("group_seats K ~p Waiting ~p Sitting ~p List ~p~n", [K, Waiting, Sitting, L]),
receive
{Pid, eat} ->
io:format("Customer ~p has arrived~n",[Pid]),
group_seats(K, Waiting + 1, Sitting, L ++ [Pid]);
{Pid, done} ->
io:format("Customer ~p has finished eating~n",[Pid]),
group_seats(K, Waiting, Sitting - 1, L)
end.
%% Sleeps for a random duration before trying to eat, then lets the controller and main know when he is done.
bar(SleepTime) ->
random:seed(now()),
timer:sleep(random:uniform(1000)),
cpid ! {self(), eat},
receive
{cpid, sit_down} ->
timer:sleep(random:uniform(SleepTime)),
cpid ! {self(), done},
main ! {self(), left}
end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment