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

Provide a lock-free reader-writer lock implementation

parent 3d2eaa78
......@@ -13,41 +13,121 @@
#ifdef __cplusplus
#if __cplusplus >= 201103L
#include <cstdint>
#include <atomic>
#include <thread>
#include <type_traits>
using namespace std;
#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>
#include <sys/syscall.h>
#include <vector>
public:
CyLock() {
_readers = 0;
}
#include <sstream>
#include <iostream>
#include <stdexcept>
void rlock(const char * context) {
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)) {
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 {
protected:
pthread_rwlock_t rwlock;
public:
CyLock() {
pthread_rwlock_init(&this->rwlock, NULL);
void wlock(const char * context) {
int retry = 0;
while (true) {
uint32_t prev_readers = _readers;
if (prev_readers == 0) {
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 {
......@@ -517,31 +597,6 @@
#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
* @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