This is an example of how a resource locker can be coded in Erlang.
For a more practical, distributed locker, see the global
module in the kernel
application of OTP.
One locker is created per resource you wish to lock. These lockers
are named and their names are stored in a public ETS table. Locker names
can be arbitary terms. This allows non-re-entrant functions to be called
exclusively with call/3
.
This is of course voluntary locking (unless you somehow arrange for the locker to be used on otherwise normal calls, e.g. with a parse transform.)
Exported Functions | |
---|---|
call/3 | Calls a non-re-entrant function. |
create_locker_table/1 | Called by start/0 . |
lock/1 | See lock/2 . |
lock/2 | Locks a resource, preventing other processes from accessing it. |
new/1 | Creates a new locker for a named resource. |
server/0 | Called by new/1 . |
start/0 | Starts the resource locking subsystem. |
test/0 | |
test2/0 | |
unlock/1 | Unlocks a resource, allowing other processes to access it. |
Internal Documented Functions | |
server/1 | Main locker server loop. |
call(Module::atom(), Function::atom(), Args::[term()]) -> term()
Calls a non-re-entrant function. Does this by first locking
the function by it's name, then calling the function, then unlocking it.
The name of the function in this case is {Module, Function, Arity}
where
Arity
is determined by the length of Args
.
create_locker_table(Parent::pid()) -> never_returns
Called by start/0
. Should not be called by user code.
lock(locker()) -> {ok, Result} | {error, Reason}
Equivalent to lock(locker(), infinity)
.
lock(locker(), Timeout::integer()) -> {ok, Result} | {error, Reason}
Locks a resource, preventing other processes from accessing it. The resource may specified by name, or by locker pid. If a locker for the named resource does not exist, one is created.
new(Name::term()) -> pid()
Creates a new locker for a named resource.
server() -> never_returns
Called by new/1
. Should not be called by user code.
start() -> pid()
Starts the resource locking subsystem. Creates an ETS table to map resource names to lockers.
test() -> term()
test2() -> term()
unlock(locker()) -> {ok, Result} | {error, Reason}
Unlocks a resource, allowing other processes to access it. The resource may specified by name, or by locker pid.
server(Queue::[pid()]) -> never_returns
Main locker server loop. Queue
is the list of pids that are
waiting for this resource; the head of this list is the pid which currently owns
the lock.