Skip to content

Instantly share code, notes, and snippets.

@awreece
Last active December 19, 2015 01:19
Show Gist options
  • Save awreece/5874585 to your computer and use it in GitHub Desktop.
Save awreece/5874585 to your computer and use it in GitHub Desktop.
increment_version() // Block all incoming readers.
while (num_readers() != 0) {} // Wait for all current readers to finish.
old_val = val
val = NULL
increment_version() // Allow readers again.
if old_val->refcount == 1
free(old_val)
Top:
while ((version = read_version()) & 1) {} // Wait for there to be no writers.
// BUG(awreece) There is a race here - if a writer comes in at the last moment
// when there were previously no readers, it would assume there were
// no readers and the reader would assume there were no writers.
increment_num_readers() // Tell the world there is one more reader.
ret_val = val
ret_val->ref_count++ // Incr refcount before signalling writers.
memory_barrier() // Make sure the world can see the bump to refcount before they see we're done.
decrement_num_readers()
if (read_version() != version) {
if (--ret_val->ref_count == 0)
free(ret_val) // We may have to clean up after racing with a delete.
goto Top
}
@awreece
Copy link
Author

awreece commented Jun 27, 2013

I feel like I really just wanted an rwspinlock. A nice rwlock implementation I saw recently was the Go rwlock which reduces the no contention reader case to a single pair of atomic adds:

if atomic.AddInt32(&rw.readerCount, 1) < 0 {
       // A writer is pending, wait for it.
       runtime_Semacquire(&rw.readerSem)
}

// Reader critical section.

if atomic.AddInt32(&rw.readerCount, -1) < 0 {
        // A writer is pending.
        if atomic.AddInt32(&rw.readerWait, -1) == 0 {
                // The last reader unblocks the writer.
                runtime_Semrelease(&rw.writerSem)
        }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment