Fix locking in LockPool
This commit is contained in:
parent
11a85ed29f
commit
1cf52b307d
@ -20,11 +20,13 @@ namespace cpputils {
|
||||
public:
|
||||
LockPool();
|
||||
~LockPool();
|
||||
void lock(const LockName &lock, std::unique_lock<std::mutex> *lockToFreeWhileWaiting = nullptr);
|
||||
void release(const LockName &lock);
|
||||
void lock(const LockName &lockName);
|
||||
void lock(const LockName &lockName, std::unique_lock<std::mutex> *lockToFreeWhileWaiting);
|
||||
void release(const LockName &lockName);
|
||||
|
||||
private:
|
||||
bool _isLocked(const LockName &lock) const;
|
||||
bool _isLocked(const LockName &lockName) const;
|
||||
template<class OuterLock> void _lock(const LockName &lockName, OuterLock *lockToFreeWhileWaiting);
|
||||
|
||||
std::vector<LockName> _lockedLocks;
|
||||
std::mutex _mutex;
|
||||
@ -41,31 +43,44 @@ namespace cpputils {
|
||||
}
|
||||
|
||||
template<class LockName>
|
||||
inline void LockPool<LockName>::lock(const LockName &lock, std::unique_lock<std::mutex> *lockToFreeWhileWaiting) {
|
||||
inline void LockPool<LockName>::lock(const LockName &lockName, std::unique_lock<std::mutex> *lockToFreeWhileWaiting) {
|
||||
ASSERT(lockToFreeWhileWaiting->owns_lock(), "Given lock must be locked");
|
||||
std::unique_lock<std::mutex> mutexLock(_mutex); // TODO Is shared_lock enough here?
|
||||
if (_isLocked(lock)) {
|
||||
// Order of locking/unlocking is important and should be the same order as everywhere else to prevent deadlocks.
|
||||
// Since when entering the function, lockToFreeWhileWaiting is already locked and mutexLock is locked afterwards,
|
||||
// the condition variable should do it in the same order. We use combinedLock for this.
|
||||
CombinedLock combinedLock(lockToFreeWhileWaiting, &mutexLock);
|
||||
_cv.wait(combinedLock, [this, &lock]{
|
||||
return !_isLocked(lock);
|
||||
// Order of locking/unlocking is important and should be the same order as everywhere else to prevent deadlocks.
|
||||
// Since when entering the function, lockToFreeWhileWaiting is already locked and mutexLock is locked afterwards,
|
||||
// the condition variable should do it in the same order. We use combinedLock for this.
|
||||
CombinedLock combinedLock(lockToFreeWhileWaiting, &mutexLock);
|
||||
_lock(lockName, &combinedLock);
|
||||
ASSERT(mutexLock.owns_lock() && lockToFreeWhileWaiting->owns_lock(), "Locks haven't been correctly relocked");
|
||||
}
|
||||
|
||||
template<class LockName>
|
||||
inline void LockPool<LockName>::lock(const LockName &lockName) {
|
||||
std::unique_lock<std::mutex> mutexLock(_mutex); // TODO Is shared_lock enough here?
|
||||
_lock(lockName, &mutexLock);
|
||||
ASSERT(mutexLock.owns_lock(), "Lock hasn't been correctly relocked");
|
||||
}
|
||||
|
||||
template<class LockName>
|
||||
template<class OuterLock>
|
||||
inline void LockPool<LockName>::_lock(const LockName &lockName, OuterLock *mutexLock) {
|
||||
if (_isLocked(lockName)) {
|
||||
_cv.wait(*mutexLock, [this, &lockName]{
|
||||
return !_isLocked(lockName);
|
||||
});
|
||||
ASSERT(mutexLock.owns_lock() && lockToFreeWhileWaiting->owns_lock(), "Locks haven't been correctly relocked");
|
||||
}
|
||||
_lockedLocks.push_back(lock);
|
||||
_lockedLocks.push_back(lockName);
|
||||
}
|
||||
|
||||
template<class LockName>
|
||||
inline bool LockPool<LockName>::_isLocked(const LockName &lock) const {
|
||||
return std::find(_lockedLocks.begin(), _lockedLocks.end(), lock) != _lockedLocks.end();
|
||||
inline bool LockPool<LockName>::_isLocked(const LockName &lockName) const {
|
||||
return std::find(_lockedLocks.begin(), _lockedLocks.end(), lockName) != _lockedLocks.end();
|
||||
}
|
||||
|
||||
template<class LockName>
|
||||
inline void LockPool<LockName>::release(const LockName &lock) {
|
||||
inline void LockPool<LockName>::release(const LockName &lockName) {
|
||||
std::unique_lock<std::mutex> mutexLock(_mutex);
|
||||
auto found = std::find(_lockedLocks.begin(), _lockedLocks.end(), lock);
|
||||
auto found = std::find(_lockedLocks.begin(), _lockedLocks.end(), lockName);
|
||||
ASSERT(found != _lockedLocks.end(), "Lock given to release() was not locked");
|
||||
_lockedLocks.erase(found);
|
||||
_cv.notify_all();
|
||||
|
@ -28,6 +28,7 @@ namespace cpputils {
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
ASSERT(_pool != nullptr, "MutexPoolLock is not locked");
|
||||
_pool->release(_lockName);
|
||||
_pool = nullptr;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user