RWlock
View SourceA concurrent Readers/Writer lock implementation built on GenServer
.
RWLock
allows multiple readers to acquire a shared (:sh_lock
) lock
simultaneously, while ensuring that only one writer (:ex_lock
) can hold
an exclusive lock at any given time.
This module manages lock ownership across processes and ensures correct
coordination between readers and writers for a given resource key (referred to as on
).
Features
- Multiple readers can hold a lock concurrently (
sh_lock
) - Only one writer can hold a lock exclusively (
ex_lock
) - Fair queueing via an internal
:queue
structure - Lock ownership tracking via process identifiers
- Automatic wake-up of waiting processes when a lock is released
Installation
The package can be installed by adding rwlock
to your list of dependencies in mix.exs
:
def deps do
[
{:rwlock, "~> 0.1.1"}
]
end
This library implements a RW Locking as a process that you would generally start under a supervision tree.
defmodule MyApp.Application do
@moduledoc false
use Application
@impl true
def start(_type, _args) do
children = [
{RWLock, name: MyApp.RWLock}
]
Supervisor.start_link(children, strategy: :one_for_one)
end
end
Example
iex> RWLock.start_link()
iex> RWLock.sh_lock(:any_term1)
:ok
iex> RWLock.sh_lock(:any_term1)
:ok
iex> RWLock.ex_lock(:any_term2)
:ok
iex> RWLock.unlock(:any_term1)
:ok
iex> RWLock.unlock(:any_term1)
:ok
iex> RWLock.unlock(:any_term2)
:ok
Lock Structure
Internally, each lock entry is a map with these keys:
%{
locked?: boolean(),
type: :ex | :sh | nil,
readers: MapSet.t(),
wlist: :queue.t(),
on: any()
}
This structure is maintained per on
key in the GenServer’s state.
Copyright and License
Copyright (c) 2025, Hamad Al Marri
This work is free. You can redistribute it and/or modify it under the terms of the MIT License. See the LICENSE file for more details.