From b617378430c02fb3c8d58258ad11ad71af226e49 Mon Sep 17 00:00:00 2001 From: Sebastian Messmer Date: Sat, 3 Oct 2015 01:23:39 +0200 Subject: [PATCH] Add a lock library --- lock/ConditionBarrier.h | 37 +++++++++++++++++++++ lock/LockPool.cpp | 1 + lock/LockPool.h | 73 +++++++++++++++++++++++++++++++++++++++++ lock/MutexPoolLock.h | 38 +++++++++++++++++++++ 4 files changed, 149 insertions(+) create mode 100644 lock/ConditionBarrier.h create mode 100644 lock/LockPool.cpp create mode 100644 lock/LockPool.h create mode 100644 lock/MutexPoolLock.h diff --git a/lock/ConditionBarrier.h b/lock/ConditionBarrier.h new file mode 100644 index 00000000..e776d5c8 --- /dev/null +++ b/lock/ConditionBarrier.h @@ -0,0 +1,37 @@ +#ifndef MESSMER_CPPUTILS_CONDITIONBARRIER_H +#define MESSMER_CPPUTILS__CONDITIONBARRIER_H + +#include +#include + +//TODO Test + +namespace cpputils { + // Like a condition variable, but without spurious wakeups. + // The waiting threads are only woken, when notify() is called. + // After a call to release(), future calls to wait() will not block anymore. + class ConditionBarrier { + public: + ConditionBarrier() :_mutex(), _cv(), _triggered(false) { + } + + void wait() { + std::unique_lock lock(_mutex); + _cv.wait(lock, [this] { + return _triggered; + }); + } + + void release() { + std::unique_lock lock(_mutex); + _triggered = true; + _cv.notify_all(); + } + private: + std::mutex _mutex; + std::condition_variable _cv; + bool _triggered; + }; +} + +#endif diff --git a/lock/LockPool.cpp b/lock/LockPool.cpp new file mode 100644 index 00000000..460417c7 --- /dev/null +++ b/lock/LockPool.cpp @@ -0,0 +1 @@ +#include "LockPool.h" diff --git a/lock/LockPool.h b/lock/LockPool.h new file mode 100644 index 00000000..2ddc2830 --- /dev/null +++ b/lock/LockPool.h @@ -0,0 +1,73 @@ +#ifndef MESSMER_CPPUTILS_LOCKPOOL_H +#define MESSMER_CPPUTILS_LOCKPOOL_H + +#include +#include +#include +#include +#include "../assert/assert.h" +#include "../macros.h" + +//TODO Test +//TODO Rename package to synchronization +//TODO Rename to MutexPool +namespace cpputils { + template + class LockPool { + public: + LockPool(); + void lock(const LockName &lock, std::unique_lock *lockToFreeWhileWaiting = nullptr); + void release(const LockName &lock); + + private: + bool _isLocked(const LockName &lock) const; + + std::vector _lockedLocks; + std::mutex _mutex; + std::condition_variable _cv; + + DISALLOW_COPY_AND_ASSIGN(LockPool); + }; + template + inline LockPool::LockPool(): _lockedLocks(), _mutex(), _cv() {} + + template + inline void LockPool::lock(const LockName &lock, std::unique_lock *lockToFreeWhileWaiting) { + std::cerr << "Aquiring lock " << lock.ToString() << std::endl; + std::unique_lock mutexLock(_mutex); // TODO Is shared_lock enough here? + std::cerr << (void*)this << " Bquiring lock " << lock.ToString() << std::endl; + if (_isLocked(lock)) { + std::cerr << " is locked " << lock.ToString() << std::endl; + if(lockToFreeWhileWaiting != nullptr) { + lockToFreeWhileWaiting->unlock(); + } + _cv.wait(mutexLock, [this, &lock]{ + return !_isLocked(lock); + }); + std::cerr << " reaquiring " << lock.ToString() << std::endl; + if(lockToFreeWhileWaiting != nullptr) { + lockToFreeWhileWaiting->lock(); + } + } + std::cerr << "Lock acquired " << lock.ToString() << std::endl; + _lockedLocks.push_back(lock); + } + + template + inline bool LockPool::_isLocked(const LockName &lock) const { + return std::find(_lockedLocks.begin(), _lockedLocks.end(), lock) != _lockedLocks.end(); + } + + template + inline void LockPool::release(const LockName &lock) { + std::cerr << "Releasing lock "< mutexLock(_mutex); + auto found = std::find(_lockedLocks.begin(), _lockedLocks.end(), lock); + ASSERT(found != _lockedLocks.end(), "Lock given to release() was not locked"); + _lockedLocks.erase(found); + _cv.notify_all(); + std::cerr << "Lock released "< + class MutexPoolLock { + public: + MutexPoolLock(LockPool *pool, const LockName &lockName): _pool(pool), _lockName(lockName) { + _pool->lock(_lockName); + } + + MutexPoolLock(LockPool *pool, const LockName &lockName, std::unique_lock *lockToFreeWhileWaiting) + : _pool(pool), _lockName(lockName) { + _pool->lock(_lockName, lockToFreeWhileWaiting); + } + + MutexPoolLock(MutexPoolLock &&rhs): _pool(rhs._pool), _lockName(rhs._lockName) { + rhs._pool = nullptr; + } + + ~MutexPoolLock() { + if (_pool != nullptr) { + _pool->release(_lockName); + _pool = nullptr; + } + } + + private: + LockPool *_pool; + LockName _lockName; + + DISALLOW_COPY_AND_ASSIGN(MutexPoolLock); + }; +} + +#endif