Add a lock library

This commit is contained in:
Sebastian Messmer 2015-10-03 01:23:39 +02:00
parent 0bb278bcdd
commit b617378430
4 changed files with 149 additions and 0 deletions

37
lock/ConditionBarrier.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef MESSMER_CPPUTILS_CONDITIONBARRIER_H
#define MESSMER_CPPUTILS__CONDITIONBARRIER_H
#include <mutex>
#include <condition_variable>
//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<std::mutex> lock(_mutex);
_cv.wait(lock, [this] {
return _triggered;
});
}
void release() {
std::unique_lock<std::mutex> lock(_mutex);
_triggered = true;
_cv.notify_all();
}
private:
std::mutex _mutex;
std::condition_variable _cv;
bool _triggered;
};
}
#endif

1
lock/LockPool.cpp Normal file
View File

@ -0,0 +1 @@
#include "LockPool.h"

73
lock/LockPool.h Normal file
View File

@ -0,0 +1,73 @@
#ifndef MESSMER_CPPUTILS_LOCKPOOL_H
#define MESSMER_CPPUTILS_LOCKPOOL_H
#include <mutex>
#include <condition_variable>
#include <vector>
#include <algorithm>
#include "../assert/assert.h"
#include "../macros.h"
//TODO Test
//TODO Rename package to synchronization
//TODO Rename to MutexPool
namespace cpputils {
template<class LockName>
class LockPool {
public:
LockPool();
void lock(const LockName &lock, std::unique_lock<std::mutex> *lockToFreeWhileWaiting = nullptr);
void release(const LockName &lock);
private:
bool _isLocked(const LockName &lock) const;
std::vector<LockName> _lockedLocks;
std::mutex _mutex;
std::condition_variable _cv;
DISALLOW_COPY_AND_ASSIGN(LockPool);
};
template<class LockName>
inline LockPool<LockName>::LockPool(): _lockedLocks(), _mutex(), _cv() {}
template<class LockName>
inline void LockPool<LockName>::lock(const LockName &lock, std::unique_lock<std::mutex> *lockToFreeWhileWaiting) {
std::cerr << "Aquiring lock " << lock.ToString() << std::endl;
std::unique_lock<std::mutex> 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<class LockName>
inline bool LockPool<LockName>::_isLocked(const LockName &lock) const {
return std::find(_lockedLocks.begin(), _lockedLocks.end(), lock) != _lockedLocks.end();
}
template<class LockName>
inline void LockPool<LockName>::release(const LockName &lock) {
std::cerr << "Releasing lock "<<lock.ToString()<<std::endl;
std::unique_lock<std::mutex> 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 "<<lock.ToString()<<std::endl;
}
}
#endif

38
lock/MutexPoolLock.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef MESSMER_CPPUTILS_LOCK_MUTEXPOOLLOCK_H
#define MESSMER_CPPUTILS_LOCK_MUTEXPOOLLOCK_H
#include "LockPool.h"
namespace cpputils {
template<class LockName>
class MutexPoolLock {
public:
MutexPoolLock(LockPool<LockName> *pool, const LockName &lockName): _pool(pool), _lockName(lockName) {
_pool->lock(_lockName);
}
MutexPoolLock(LockPool<LockName> *pool, const LockName &lockName, std::unique_lock<std::mutex> *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<LockName> *_pool;
LockName _lockName;
DISALLOW_COPY_AND_ASSIGN(MutexPoolLock);
};
}
#endif