TheEagle
TheEagle

Reputation: 117

Erlang bounded buffer test-program

I'm trying to learn some basic Erlang and I want to write a test-program for this bounded buffer(old exam-question) where I have one process to invoke the put-function multiple times and another process to invoke the get-method multiple times. I get an error I don't understand. Here's the bounded buffer:

-module(bbuffer).
-export([start/1, get/1, put/2]).

%Creates new buffer of size N and returns its handle.
start(N) -> 
spawn(fun () -> loop ([], N) end).

% L is the queue, N is the number of free slots
loop(L, N) ->
receive
    {get, P, Ref} when L /= [] ->
        [X|Xs] = L,
        P ! {get_reply, Ref, X},
        loop(Xs, N + 1);

    {put, P, Ref, Y} when N > 0 ->
        P ! {put_reply, Ref},
        loop(L ++ [Y], N - 1)
end.

get(B) ->
    Ref = make_ref(), %Unique value to identify messages
    B ! {get, self(), Ref}, %Send message to process B

    receive
        {get_reply, Ref, X} -> X
    end.

put(B, X) ->
    Ref = make_ref(),
    B ! {put, self(), Ref, X},

    receive
        {put_reply, Ref} -> ok
end.    

Here's my code:

-module(main).
-export([start/1]).

start(N) -> 
    Pid = bbuffer:start(N),
    spawn(fun () -> insert(N, Pid) end),
    spawn(fun () -> take(N, Pid) end). 


insert(N, Pid) when N > 0 -> 
    io:format("INSERT  ~n"),
    bbuffer:put(Pid, N),
    insert(N - 1, Pid).

take(N, Pid) when N > 0 ->
    io:format("TAKE  ~n"),
    bbuffer:get(Pid),
    take(N - 1, Pid).

Here's the error I get:

Error in process <0.62.0> with exit value:
{function_clause,[{main,take,[-1,<0.60.0>],[{file,"main.erl"},{line,19}]}]}


Error in process <0.61.0> with exit value:
{function_clause,[{main,insert,[-1,<0.60.0>],[{file,"main.erl"},{line,13}]}]}

The program runs and loops the N times but crashes. Can someone explain why my solution doesn't work or present an idea for another solution? Thank you.

Upvotes: 1

Views: 126

Answers (1)

Dogbert
Dogbert

Reputation: 222288

You need to have a base-case for the recursive functions take and insert that do nothing. Erlang does not ignore a function call if none of its clauses match -- it crashes that process with an error.

insert(N, Pid) when N > 0 -> 
    io:format("INSERT  ~n"),
    bbuffer:put(Pid, N),
    insert(N - 1, Pid).
insert(_N, _Pid) ->
    ok

take(N, Pid) when N > 0 ->
    io:format("TAKE  ~n"),
    bbuffer:get(Pid),
    take(N - 1, Pid).
take(_N, _Pid) ->
    ok

Upvotes: 1

Related Questions