Last active
September 17, 2019 22:48
-
-
Save Connicpu/5fa2d83725dff9111aac98c170ac212a to your computer and use it in GitHub Desktop.
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
#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; | |
} |
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
#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