Skip to content

Instantly share code, notes, and snippets.

@Connicpu
Last active September 17, 2019 22:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Connicpu/5fa2d83725dff9111aac98c170ac212a to your computer and use it in GitHub Desktop.
Save Connicpu/5fa2d83725dff9111aac98c170ac212a to your computer and use it in GitHub Desktop.
#include <rwlock.h>
#include <memory>
#include <stdio.h>
int main() {
RwLock<int> data{ 0 };
{
auto write = data.Write();
*write += 1;
// write is dropped and unlock is called
}
{
auto read = data.Read();
printf("%d", *read);
// read is dropped and unlock is called
}
return 0;
}
#include <utility> // std::move
#ifdef WIN32
#include <Windows.h> // SRWLOCK
#else
#include <pthread.h> // pthread_rwlock
#endif
struct RwLockPrimitive {
#ifdef WIN32
mutable SRWLOCK lock = SRWLOCK_INIT;
#else
mutable pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER;
#endif
RwLockPrimitive() = default;
~RwLockPrimitive() {
#ifdef WIN32
// nothing to do here, they don't require destruction
#else
pthread_rwlock_destroy(&lock);
#endif
}
// The address of the lock must be stable on both windows and *nix, so this structure cannot be moved once initialized.
RwLockPrimitive(const RwLockPrimitive &) = delete;
RwLockPrimitive(RwLockPrimitive &&) = delete;
RwLockPrimitive &operator=(const RwLockPrimitive &) = delete;
RwLockPrimitive &operator=(RwLockPrimitive &&) = delete;
// Simple lock and unlock functions
void LockRead() const {
#ifdef WIN32
AcquireSRWLockShared(&lock);
#else
pthread_rwlock_rdlock(&lock);
#endif
}
void UnlockRead() const {
#ifdef WIN32
ReleaseSRWLockShared(&lock);
#else
pthread_rwlock_unlock(&lock);
#endif
}
void LockWrite() const {
#ifdef WIN32
AcquireSRWLockExclusive(&lock);
#else
pthread_rwlock_wrlock(&lock);
#endif
}
void UnlockWrite() const {
#ifdef WIN32
ReleaseSRWLockExclusive(&lock);
#else
pthread_rwlock_unlock(&lock);
#endif
}
};
template <typename T>
class RwLock {
public:
RwLock(T &&data) : data(std::move(data)) {}
class ReadGuard {
const RwLock *lock;
public:
ReadGuard(const RwLock *lock = nullptr) : lock(lock) {
if (lock) {
lock->lock.LockRead();
}
}
~ReadGuard() {
Unlock();
}
ReadGuard(const ReadGuard &) = delete;
ReadGuard(ReadGuard &&other) : lock(other.lock) {
other.lock = nullptr;
}
ReadGuard &operator=(const ReadGuard &) = delete;
ReadGuard &operator=(ReadGuard &&other) {
std::swap(lock, other.lock);
other.Unlock();
}
const T &operator*() const {
return lock->data;
}
const T *operator->() const {
return &lock->data;
}
const T *Get() const {
return &lock->data;
}
void Unlock() {
if (lock) {
lock->lock.UnlockRead();
lock = nullptr;
}
}
};
class WriteGuard {
const RwLock *lock;
public:
WriteGuard(const RwLock *lock = nullptr) : lock(lock) {
if (lock) {
lock->lock.LockWrite();
}
}
~WriteGuard() {
Unlock();
}
WriteGuard(const WriteGuard &) = delete;
WriteGuard(WriteGuard &&other) : lock(other.lock) {
other.lock = nullptr;
}
WriteGuard &operator=(const WriteGuard &) = delete;
WriteGuard &operator=(WriteGuard &&other) {
std::swap(lock, other.lock);
other.Unlock();
}
T &operator*() const {
return lock->data;
}
T *operator->() const {
return &lock->data;
}
T *Get() const {
return &lock->data;
}
void Unlock() {
if (lock) {
lock->lock.UnlockWrite();
lock = nullptr;
}
}
};
ReadGuard Read() const {
return{this};
}
WriteGuard Write() const {
return{this};
}
private:
mutable T data;
RwLockPrimitive lock;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment