Skip to content

Instantly share code, notes, and snippets.

@alreadydone
Forked from yizhang82/rw_spin_lock.h
Created November 15, 2018 06:53
Show Gist options
  • Save alreadydone/24871e24cb3ecdb63d25219a9984375d to your computer and use it in GitHub Desktop.
Save alreadydone/24871e24cb3ecdb63d25219a9984375d to your computer and use it in GitHub Desktop.
portable lock-free reader/writer lock for C++
class rw_spin_lock
{
public:
rw_spin_lock()
{
_readers = 0;
}
public:
void acquire_reader()
{
int retry = 0;
while (true)
{
uint32_t prev_readers = _readers;
if (prev_readers != HAS_WRITER)
{
uint32_t new_readers = prev_readers + 1;
if (_readers.compare_exchange_weak(prev_readers, new_readers))
{
// we've won the race
return;
}
}
retry++;
if (retry > RETRY_THRESHOLD)
{
retry = 0;
this_thread::yield();
}
}
}
void release_reader()
{
int retry = 0;
while (true)
{
uint32_t prev_readers = _readers;
if (prev_readers != HAS_WRITER && prev_readers > 0)
{
uint32_t new_readers = prev_readers - 1;
if (_readers.compare_exchange_weak(prev_readers, new_readers))
{
// we've won the race
return;
}
}
retry++;
if (retry > RETRY_THRESHOLD)
{
retry = 0;
this_thread::yield();
}
}
}
void acquire_writer()
{
int retry = 0;
while (true)
{
uint32_t prev_readers = _readers;
if (prev_readers == 0)
{
if (_readers.compare_exchange_weak(prev_readers, HAS_WRITER))
{
// we've won the race
return;
}
}
retry++;
if (retry > RETRY_THRESHOLD)
{
// save some cpu cycles
retry = 0;
this_thread::yield();
}
}
}
void release_writer()
{
int retry = 0;
while (true)
{
uint32_t prev_readers = _readers;
if (prev_readers == HAS_WRITER)
{
if (_readers.compare_exchange_weak(prev_readers, 0))
{
// we've won the race
return;
}
}
retry++;
if (retry > RETRY_THRESHOLD)
{
// save some cpu cycles
retry = 0;
this_thread::yield();
}
}
}
private:
const uint32_t HAS_WRITER = 0xffffffff;
const int RETRY_THRESHOLD = 100;
std::atomic<uint32_t> _readers;
};
class reader_lock
{
public:
reader_lock(rw_spin_lock &lock) : _lock(lock)
{
_lock.acquire_reader();
}
~reader_lock()
{
_lock.release_reader();
}
private:
rw_spin_lock &_lock;
};
class writer_lock
{
public:
writer_lock(rw_spin_lock &lock) : _lock(lock)
{
_lock.acquire_writer();
}
~writer_lock()
{
_lock.release_writer();
}
private:
rw_spin_lock &_lock;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment