Created
April 21, 2016 19:49
-
-
Save AndriSig/7b06ab429cd0023893610ba153f8b901 to your computer and use it in GitHub Desktop.
This file contains 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
-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