How to implement an efficient Readers-Writer lock?

I read a blog about Readers-Writer Lock here Implementing reader-writer locks last week. The original code was written in Golang. And I attempted to rewrite the code in Julia.

The reader count based implementation is straight forward in Julia:

mutable struct ReaderCountRWLock
    m::Threads.Mutex
    reader_count::Int
    ReaderCountRWLock() = new(Threads.Mutex(), 0)
end

function read_lock(l::ReaderCountRWLock)
    lock(l.m) do
    l.reader_count += 1
    end
end

function read_unlock(l::ReaderCountRWLock)
    lock(l.m) do
        l.reader_count -= 1
        if l.reader_count < 0
            error("reader count negative")
        end
    end
end

function write_lock(l::ReaderCountRWLock)
    while true
        lock(l.m)
        if l.reader_count > 0
            unlock(l.m)
        else
            break
        end
    end
end

function write_unlock(l::ReaderCountRWLock)
    unlock(l.m)
end

But for the last part in that blog, A more efficient writer-preferring RW lock, it mentions that there’s a more efficient implementation in Golang here https://golang.org/src/sync/rwmutex.go?s=987:1319#L18 Unfortunately, I don’t know what’s the equivalent function of runtime_SemacquireMutex in Julia.

So my question is: how to implement the equivalent Readers-Writer lock in Julia?

2 Likes

I’ve recently had the same need and I was looking for something like that but I found nothing. I didn’t want to block other threads with every read operation, so the hack I’m using right now is a semaphore with a max. capacity equal to the number of readers:

sem = Semaphore(num_readers)

read_lock(sem::Semaphore) = acquire(sem)
read_unlock(sem::Semaphore) = release(sem)

function write_lock(sem::Semaphore)
    for i=1:num_readers
        acquire(sem)
    end
end

function write_unlock(sem::Semaphore)
    for i=1:num_readers
        release(sem)
    end
end
2 Likes

I’m not sure if this is the right question to ask, because I believe it is notoriously difficult to get this right.

Doesn’t it deadlock when there are two or more writers?

1 Like

Yes. It was thought to be used with a single writer. With +1 writers it gets trickier and I wouldn’t know how to solve it off the top of my head.

So let me be more specific about the questions I would ask:

  • is there any Julia support for OS provided rw-locks?
  • if not, are rw-locks of any value with regard to the multi threading and distribution implementation of Julia (aka Threads and Distributed?

You wouldn’t want to use locks for OS native threads. You’d need to yield to Julia scheduler and not to OS while waiting.

I don’t think it’d be hard to implement a simple reader-writer lock based on Threads.Condition. Maybe look at The Art of Multiprocessor Programming - 2nd Edition or Shared-Memory Synchronization | Synthesis Lectures on Computer Architecture

You can also create a reader-writer lock from multiple channels, although it is rather a mental exercise than a useful implementation: Locks · Reagents (It should be a totally valid one, though)

2 Likes