#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::unique_lock mutexLock(_mutex); // TODO Is shared_lock enough here? if (_isLocked(lock)) { if(lockToFreeWhileWaiting != nullptr) { lockToFreeWhileWaiting->unlock(); } _cv.wait(mutexLock, [this, &lock]{ return !_isLocked(lock); }); if(lockToFreeWhileWaiting != nullptr) { lockToFreeWhileWaiting->lock(); } } _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::unique_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(); } } #endif