Reputation: 117
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
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