Extended Read-Write Locks

TanayLabUtilities.ExtendedReadWriteLocks Module

Enhanced (reentrant) read-write locks.

These add functionality on top of "any" simple read-write locks, such as ConcurrentUtils.ReadWriteLock or MostlyReadWriteLock . Specifically, they allow querying the status of the lock.

We also provide aliases lock_write and unlock_write to lock and unlock for clearer code. These will work for "any" read-write lock, basic or extended.

The locking and unlocking functions are extended to generate @debug log messages for the operation(s). If a named what parameter is given to the function(s), it is included in the message. Enabling debugging for ExtendedReadWriteLocks will therefore log each and every operation, which is a blunt tool, but useful in desperate cases to debug multi-threaded locking behavior.

Note

There's no standard abstract type for "any" read-write lock. Defining a new one doesn't help since ConcurrentUtils.ReadWriteLock won't use it. Sigh.

using Base.Threads
using ConcurrentUtils

read_write_lock = ExtendedReadWriteLock()

@assert !has_write_lock(read_write_lock)
@assert !has_read_lock(read_write_lock)

lock_write(read_write_lock; what = "top_write") do
    @assert has_write_lock(read_write_lock)
    @assert has_read_lock(read_write_lock)

    lock_write(read_write_lock; what = "nested_write") do
        @assert has_write_lock(read_write_lock)
        @assert has_read_lock(read_write_lock)
    end

    lock_read(read_write_lock; what = "nested_read") do
        @assert has_write_lock(read_write_lock)
        @assert has_read_lock(read_write_lock)
    end
end

@assert !has_write_lock(read_write_lock)
@assert !has_read_lock(read_write_lock)

# output


using Base.Threads
using ConcurrentUtils

read_write_lock = ExtendedReadWriteLock()

@assert !has_write_lock(read_write_lock)
@assert !has_read_lock(read_write_lock)

lock_read(read_write_lock; what = "top_read") do
    @assert !has_write_lock(read_write_lock)
    @assert has_read_lock(read_write_lock)

    lock_read(read_write_lock; what = "nested_read") do
        @assert !has_write_lock(read_write_lock)
        @assert has_read_lock(read_write_lock)
    end
end

@assert !has_write_lock(read_write_lock)
@assert !has_read_lock(read_write_lock)

# output


using Base.Threads
using ConcurrentUtils

read_write_lock = ExtendedReadWriteLock()

@assert !has_write_lock(read_write_lock)
@assert !has_read_lock(read_write_lock)

lock_read(read_write_lock; what = "top_read") do
    @assert !has_write_lock(read_write_lock)
    @assert has_read_lock(read_write_lock)

    lock_write(read_write_lock; what = "nested_write") do
        @assert false
    end
end

# output

ERROR: trying to obtain write lock for: nested_write
while holding read lock:

TanayLabUtilities.ExtendedReadWriteLocks.ExtendedReadWriteLock Type
struct ExtendedReadWriteLock{BasicReadWriteLock} <: AbstractLock ... end
where {ReadWriteLockType <: AbstractLock}

ExtendedReadWriteLock(basic_read_write_lock::ReadWriteLockType)::ExtendedReadWriteLock{ReadWriteLockType}
where {ReadWriteLockType <: AbstractLock}

ExtendedReadWriteLock()::ExtendedReadWriteLock{MostlyReadWriteLock}

A read-write lock that supports extended operations (querying lock status). The basic_read_write_lock provides the core functionality. It is wrapped to support the additional operations.

TanayLabUtilities.ExtendedReadWriteLocks.has_read_lock Function
has_read_lock(read_write_lock::ExtendedReadWriteLock; read_only::Bool = false)::Bool

Return whether the current task has a read lock or the write lock. If read_only is set, then this will only return whether the current task as a read lock.

Index