duncanatt
4/20/2017 - 9:44 AM

Concurrent Programming in Erlang - Week 1 Assignment

Concurrent Programming in Erlang - Week 1 Assignment

%% Based on code from
%%   Erlang Programming
%%   Francecso Cesarini and Simon Thompson
%%   O'Reilly, 2008
%%   http://oreilly.com/catalog/9780596518189/
%%   http://www.erlangprogramming.org/
%%   (c) Francesco Cesarini and Simon Thompson

-module(frequency2).
-export([start/0,allocate/0,deallocate/1,stop/0,clear/0]).
-export([init/0]).

%% These are the start functions used to create and
%% initialize the server.

start() ->
    register(frequency,
	     spawn(frequency2, init, [])).

init() ->
  Frequencies = {get_frequencies(), []},
  loop(Frequencies).

% Hard Coded
get_frequencies() -> [10,11,12,13,14,15].

%% The Main Loop

loop(Frequencies) ->
  receive
    {request, Pid, allocate} ->
      {NewFrequencies, Reply} = allocate(Frequencies, Pid),

      % Simulate overload.
      timer:sleep(2000),

      Pid ! {reply, Reply},
      loop(NewFrequencies);
    {request, Pid , {deallocate, Freq}} ->
      NewFrequencies = deallocate(Frequencies, Freq),

      % Simulate overload.
      timer:sleep(2000),

      Pid ! {reply, ok},
      loop(NewFrequencies);
    {request, Pid, stop} ->
      Pid ! {reply, stopped}
  end.

%% Functional interface

allocate() ->
    % Clear any unnecessary messages that might be sent in response to timed
    % out requests, so that we will only have the reply of the new request that
    % is about to be sent to the server.
    clear(),

    frequency ! {request, self(), allocate},
    receive
	    {reply, Reply} -> Reply
    after 1000 -> timeout
    end.

deallocate(Freq) ->
    % Clear any unnecessary messages that might be sent in response to timed
    % out requests, so that we will only have the reply of the new request that
    % is about to be sent to the server.
    clear(),

    frequency ! {request, self(), {deallocate, Freq}},
    receive
	    {reply, Reply} -> Reply
    after 1000 -> timeout
    end.

stop() ->
    frequency ! {request, self(), stop},
    receive
	    {reply, Reply} -> Reply
    end.


%% The Internal Help Functions used to allocate and
%% deallocate frequencies.

allocate({[], Allocated}, _Pid) ->
  {{[], Allocated}, {error, no_frequency}};
allocate({[Freq|Free], Allocated}, Pid) ->
  {{Free, [{Freq, Pid}|Allocated]}, {ok, Freq}}.

deallocate({Free, Allocated}, Freq) ->
  NewAllocated=lists:keydelete(Freq, 1, Allocated),
  {[Freq|Free],  NewAllocated}.

% Clears the messages from the mailbox. It avoids blocking when there are no
% messages by using a timeout of 0. And it also avoids looping forever by
% not calling itself again once the 'after 0' clause is taken. Before that,
% the function calls itself indefinitely until the whole mailbox has been
% emptied of all messages. It also prints each message that is chucked out of
% the mailbox.
clear() ->
  receive
    Msg ->
      io:format("Clearing message: ~p~n", [Msg]),
      clear()
  after 0 -> ok
  end.