-
-
Save alreadydone/24871e24cb3ecdb63d25219a9984375d to your computer and use it in GitHub Desktop.
portable lock-free reader/writer lock for C++
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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