Message passing
Barrier synchronisation
Resource allocation
Readers and writers
N processes must wait for the slowest before continuing with the next activity
Widely used in parallel programming
reach_wait(Server) -> Ref = make_ref(), Server ! {reach, self(), Ref}, receive {ack, Ref} -> true end. start(N) -> Pid = spawn(fun() -> coordinator(N,N,[]) end), register(coordinator, Pid). coordinator(N,0,Ps) -> [ From ! {ack, Ref} || {From, Ref} <- Ps ], coordinator(N,N,[]) ; coordinator(N,M,Ps) -> receive {reach, From, Ref} -> coordinator(N,M-1, [ {From,Ref} | Ps]) end.
A controller controls access to copies of some resources (of the same kind)
Clients requiring multiple resources should not ask for resources one at a time
Clients make requests to take or return any number of the resources
A request should only succeed if there are
sufficiently many resources available (see line 4
)
Otherwise the request must block
Function lists:sublist
returns a slice of a
list
(more here)
loop(Resources) -> Available = length(Resources), receive {req, From, Ref, Number} when Number =< Available -> From ! {res, Ref, lists:sublist(Resources, Number)}, loop(lists:sublist(Resources, Number+1, Available)) ; {ret, List} -> loop(lists:append(Resources, List)) end. start(Init) -> Pid = spawn (fun () -> loop(Init) end), register(rserver, Pid). request(N) -> Ref = make_ref(), rserver ! {req, self(), Ref, N}, receive {res, Ref, List} -> List end. release(List) -> rserver ! {ret, List}, ok
> c(ralloc). {ok,ralloc} > ralloc:start([1,1,1,1]). true > ralloc:request(3). [1,1,1] > ralloc:release([1]). ok > ralloc:request(2). [1,1] > ralloc:request(10).
Two kinds of processes share access to a “database”
Readers examine the contents
Writers examine and modify data
Readers and writers in a few lines
loop(Rs, Ws) -> receive {start_read, From, Ref} when Ws =:= 0 -> From ! {ok_to_read, Ref}, loop(Rs+1,Ws) ; {start_write, From, Ref} when Ws =:= 0 and Rs =:= 0 -> From ! {ok_to_write, Ref}, loop(Rs, Ws+1) ; end_read -> loop(Rs-1, Ws) ; end_write -> loop(Rs, Ws-1) end.
<received event>, <condition> / <triggered event>
loop() -> receive {start_read, From, Ref} -> From ! {ok_to_read, Ref}, loop_read(1), loop() ; {start_write, From, Ref} -> From ! {ok_to_write, Ref}, receive end_write -> loop() end end. loop_read(0) -> ok ; loop_read(Rs) -> receive {start_read, From, Ref} -> From ! {ok_to_read, Ref}, loop_read(Rs+1) ; end_read -> loop_read(Rs-1) ; {start_write, From, Ref} -> [ receive end_read -> ok end || _ <- lists:seq(1,Rs) ], From ! {ok_to_write, Ref}, receive end_write -> ok end end.
At top-level function loop
relies on the fairness property
of Erlang (i.e. the oldest message that matches any guard
is processed)
Function loop_read
implements fairness
Line [ receive end_read -> ok end || _ <- lists:seq(1,Rs) ]
performs as many receive
as the number Rs