diff options
author | Sven Gothel <[email protected]> | 2020-09-28 09:38:53 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2020-09-28 09:38:53 +0200 |
commit | 6653ce757add3cc732e84d7cd59f15472c57a044 (patch) | |
tree | 3b98800c2afbf22e8a508a9c4104e804afef65ec /api | |
parent | 2fef12dfd25d834429284c50669aac0ec9753979 (diff) |
LFRingbuffer: Use std::lock(..) on operations waiting for either read and/or write operations to complete
std::lock(..) allows us to wait for either order of lock-able mutex in a list using try_lock.
Global operations like drop, clear, reset etc are unaware of the ringbuffer utilization and
need to wait for the global syncMulti* read and write locks in any order.
std::scoped_lock can't be used, as we utilize std::condition_variable.wait(..)
and don't want to 'mix and match' the locking type.
Diffstat (limited to 'api')
-rw-r--r-- | api/direct_bt/LFRingbuffer.hpp | 46 |
1 files changed, 26 insertions, 20 deletions
diff --git a/api/direct_bt/LFRingbuffer.hpp b/api/direct_bt/LFRingbuffer.hpp index 01ac3c00..5c94167b 100644 --- a/api/direct_bt/LFRingbuffer.hpp +++ b/api/direct_bt/LFRingbuffer.hpp @@ -202,8 +202,9 @@ template <typename T, std::nullptr_t nullelem> class LFRingbuffer : public Ringb int dropImpl (const int count) noexcept { // locks ringbuffer completely (read/write), hence no need for local copy nor wait/sync etc - std::unique_lock<std::mutex> lockMultiRead(syncMultiRead); // RAII-style acquire and relinquish via destructor - std::unique_lock<std::mutex> lockMultiWrite(syncMultiWrite); // ditto + std::unique_lock<std::mutex> lockMultiRead(syncMultiRead, std::defer_lock); // utilize std::lock(r, w), allowing mixed order waiting on read/write ops + std::unique_lock<std::mutex> lockMultiWrite(syncMultiWrite, std::defer_lock); // otherwise RAII-style relinquish via destructor + std::lock(lockMultiRead, lockMultiWrite); const int dropCount = std::min(count, size.load()); if( 0 == dropCount ) { @@ -333,18 +334,18 @@ template <typename T, std::nullptr_t nullelem> class LFRingbuffer : public Ringb : capacityPlusOne(_source.capacityPlusOne), array(newArray(capacityPlusOne)), readPos(0), writePos(0), size(0) { - std::unique_lock<std::mutex> lockMultiReadS(_source.syncMultiRead); - std::unique_lock<std::mutex> lockMultiWriteS(_source.syncMultiWrite); - std::unique_lock<std::mutex> lockMultiRead(syncMultiRead); - std::unique_lock<std::mutex> lockMultiWrite(syncMultiWrite); + std::unique_lock<std::mutex> lockMultiReadS(_source.syncMultiRead, std::defer_lock); // utilize std::lock(r, w), allowing mixed order waiting on read/write ops + std::unique_lock<std::mutex> lockMultiWriteS(_source.syncMultiWrite, std::defer_lock); // otherwise RAII-style relinquish via destructor + std::lock(lockMultiReadS, lockMultiWriteS); // *this instance does not exist yet cloneFrom(false, _source); } LFRingbuffer& operator=(const LFRingbuffer &_source) noexcept { - std::unique_lock<std::mutex> lockMultiReadS(_source.syncMultiRead); - std::unique_lock<std::mutex> lockMultiWriteS(_source.syncMultiWrite); - std::unique_lock<std::mutex> lockMultiRead(syncMultiRead); - std::unique_lock<std::mutex> lockMultiWrite(syncMultiWrite); + std::unique_lock<std::mutex> lockMultiReadS(_source.syncMultiRead, std::defer_lock); // utilize std::lock(r, w), allowing mixed order waiting on read/write ops + std::unique_lock<std::mutex> lockMultiWriteS(_source.syncMultiWrite, std::defer_lock); // otherwise RAII-style relinquish via destructor + std::unique_lock<std::mutex> lockMultiRead(syncMultiRead, std::defer_lock); // same for *this instance! + std::unique_lock<std::mutex> lockMultiWrite(syncMultiWrite, std::defer_lock); + std::lock(lockMultiReadS, lockMultiWriteS, lockMultiRead, lockMultiWrite); if( this == &_source ) { return *this; @@ -364,20 +365,23 @@ template <typename T, std::nullptr_t nullelem> class LFRingbuffer : public Ringb int capacity() const noexcept override { return capacityPlusOne-1; } void clear() noexcept override { - std::unique_lock<std::mutex> lockMultiRead(syncMultiRead); // RAII-style acquire and relinquish via destructor - std::unique_lock<std::mutex> lockMultiWrite(syncMultiWrite); // ditto + std::unique_lock<std::mutex> lockMultiRead(syncMultiRead, std::defer_lock); // utilize std::lock(r, w), allowing mixed order waiting on read/write ops + std::unique_lock<std::mutex> lockMultiWrite(syncMultiWrite, std::defer_lock); // otherwise RAII-style relinquish via destructor + std::lock(lockMultiRead, lockMultiWrite); clearImpl(); } void reset(const T * copyFrom, const int copyFromCount) noexcept override { - std::unique_lock<std::mutex> lockMultiRead(syncMultiRead); // RAII-style acquire and relinquish via destructor - std::unique_lock<std::mutex> lockMultiWrite(syncMultiWrite); // ditto + std::unique_lock<std::mutex> lockMultiRead(syncMultiRead, std::defer_lock); // utilize std::lock(r, w), allowing mixed order waiting on read/write ops + std::unique_lock<std::mutex> lockMultiWrite(syncMultiWrite, std::defer_lock); // otherwise RAII-style relinquish via destructor + std::lock(lockMultiRead, lockMultiWrite); resetImpl(copyFrom, copyFromCount); } void reset(const std::vector<T> & copyFrom) noexcept override { - std::unique_lock<std::mutex> lockMultiRead(syncMultiRead); // RAII-style acquire and relinquish via destructor - std::unique_lock<std::mutex> lockMultiWrite(syncMultiWrite); // ditto + std::unique_lock<std::mutex> lockMultiRead(syncMultiRead, std::defer_lock); // utilize std::lock(r, w), allowing mixed order waiting on read/write ops + std::unique_lock<std::mutex> lockMultiWrite(syncMultiWrite, std::defer_lock); // otherwise RAII-style relinquish via destructor + std::lock(lockMultiRead, lockMultiWrite); resetImpl(copyFrom.data(), copyFrom.size()); } @@ -424,8 +428,9 @@ template <typename T, std::nullptr_t nullelem> class LFRingbuffer : public Ringb } void waitForFreeSlots(const int count) noexcept override { - std::unique_lock<std::mutex> lockMultiWrite(syncMultiWrite); // RAII-style acquire and relinquish via destructor - std::unique_lock<std::mutex> lockRead(syncRead); // RAII-style acquire and relinquish via destructor + std::unique_lock<std::mutex> lockMultiWrite(syncMultiWrite, std::defer_lock); // utilize std::lock(r, w), allowing mixed order waiting on read/write ops + std::unique_lock<std::mutex> lockRead(syncRead, std::defer_lock); // otherwise RAII-style relinquish via destructor + std::lock(lockMultiWrite, lockRead); while( capacityPlusOne - 1 - size < count ) { cvRead.wait(lockRead); @@ -433,8 +438,9 @@ template <typename T, std::nullptr_t nullelem> class LFRingbuffer : public Ringb } void recapacity(const int newCapacity) override { - std::unique_lock<std::mutex> lockMultiRead(syncMultiRead); - std::unique_lock<std::mutex> lockMultiWrite(syncMultiWrite); + std::unique_lock<std::mutex> lockMultiRead(syncMultiRead, std::defer_lock); // utilize std::lock(r, w), allowing mixed order waiting on read/write ops + std::unique_lock<std::mutex> lockMultiWrite(syncMultiWrite, std::defer_lock); // otherwise RAII-style relinquish via destructor + std::lock(lockMultiRead, lockMultiWrite); if( capacityPlusOne == newCapacity+1 ) { return; |