Commit 00ba2251 authored by Xavier Thompson's avatar Xavier Thompson

Provide a lock-free reader-writer lock implementation

parent 3d2eaa78
...@@ -13,41 +13,121 @@ ...@@ -13,41 +13,121 @@
#ifdef __cplusplus #ifdef __cplusplus
#if __cplusplus >= 201103L #if __cplusplus >= 201103L
#include <cstdint>
#include <atomic> #include <atomic>
#include <thread>
#include <type_traits>
using namespace std; using namespace std;
#define CyObject_ATOMIC_REFCOUNT_TYPE atomic_int #define CyObject_ATOMIC_REFCOUNT_TYPE atomic_int
#include <pthread.h>
#include <sys/types.h> class CyLock {
protected:
const uint32_t HAS_WRITER = 0xffffffff;
const int RETRY_THRESHOLD = 100;
std::atomic<uint32_t> _readers;
#include <unistd.h> public:
#include <sys/syscall.h> CyLock() {
#include <vector> _readers = 0;
}
#include <sstream> void rlock(const char * context) {
#include <iostream> int retry = 0;
#include <stdexcept> 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)) {
return;
}
}
retry++;
if (retry > RETRY_THRESHOLD) {
retry = 0;
std::this_thread::yield();
}
}
}
#include <type_traits> int tryrlock() {
int retry = 0;
while (true) {
uint32_t prev_readers = _readers;
if (prev_readers == HAS_WRITER) {
return -1;
}
uint32_t new_readers = prev_readers + 1;
if (_readers.compare_exchange_weak(prev_readers, new_readers)) {
return 0;
}
retry++;
if (retry > RETRY_THRESHOLD) {
retry = 0;
std::this_thread::yield();
}
}
}
void unrlock() {
int retry = 0;
while (true) {
uint32_t prev_readers = _readers;
if (prev_readers + 1 > 1) {
uint32_t new_readers = prev_readers - 1;
if (_readers.compare_exchange_weak(prev_readers, new_readers)) {
return;
}
}
else {
return;
}
retry++;
if (retry > RETRY_THRESHOLD) {
retry = 0;
std::this_thread::yield();
}
}
}
class CyLock { void wlock(const char * context) {
protected: int retry = 0;
pthread_rwlock_t rwlock; while (true) {
public: uint32_t prev_readers = _readers;
CyLock() { if (prev_readers == 0) {
pthread_rwlock_init(&this->rwlock, NULL); if (_readers.compare_exchange_weak(prev_readers, HAS_WRITER)) {
return;
}
}
retry++;
if (retry > RETRY_THRESHOLD) {
retry = 0;
std::this_thread::yield();
}
}
} }
~CyLock() {
pthread_rwlock_destroy(&this->rwlock); int trywlock() {
uint32_t prev_readers = _readers;
if (prev_readers == 0) {
return _readers.compare_exchange_weak(prev_readers, HAS_WRITER) - 1;
}
return -1;
}
void unwlock() {
uint32_t prev_readers = _readers;
if (prev_readers == HAS_WRITER) {
_readers.compare_exchange_weak(prev_readers, 0);
}
return;
} }
void wlock(const char * context);
void rlock(const char * context);
void unwlock();
void unrlock();
int tryrlock();
int trywlock();
}; };
struct CyPyObject { struct CyPyObject {
...@@ -517,31 +597,6 @@ ...@@ -517,31 +597,6 @@
#endif /* __cplusplus */ #endif /* __cplusplus */
void CyLock::rlock(CYTHON_UNUSED const char *context) {
pthread_rwlock_rdlock(&this->rwlock);
}
int CyLock::tryrlock() {
return pthread_rwlock_tryrdlock(&this->rwlock);
}
void CyLock::unrlock() {
pthread_rwlock_unlock(&this->rwlock);
}
void CyLock::wlock(CYTHON_UNUSED const char *context) {
pthread_rwlock_wrlock(&this->rwlock);
}
int CyLock::trywlock() {
return pthread_rwlock_trywrlock(&this->rwlock);
}
void CyLock::unwlock() {
pthread_rwlock_unlock(&this->rwlock);
}
/* /*
* Atomic counter increment and decrement implementation based on * Atomic counter increment and decrement implementation based on
* @source: https://www.boost.org/doc/libs/1_73_0/doc/html/atomic/usage_examples.html * @source: https://www.boost.org/doc/libs/1_73_0/doc/html/atomic/usage_examples.html
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment