Compare commits
No commits in common. "56ee5c3aed83acdaf92d39d0b0b8707a5f9fc057" and "02651c793eb848faf18751fdf40de0bcbb6db9f4" have entirely different histories.
56ee5c3aed
...
02651c793e
5 changed files with 30 additions and 486 deletions
|
@ -5,7 +5,6 @@ set(UDPC_VERSION 1.0)
|
||||||
|
|
||||||
set(UDPC_SOURCES
|
set(UDPC_SOURCES
|
||||||
src/UDPConnection.cpp
|
src/UDPConnection.cpp
|
||||||
src/CXX11_shared_spin_lock.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
add_compile_options(
|
add_compile_options(
|
||||||
|
@ -63,7 +62,6 @@ if(CMAKE_BUILD_TYPE MATCHES "Debug")
|
||||||
find_package(GTest QUIET)
|
find_package(GTest QUIET)
|
||||||
if(GTEST_FOUND)
|
if(GTEST_FOUND)
|
||||||
set(UDPC_UnitTest_SOURCES
|
set(UDPC_UnitTest_SOURCES
|
||||||
src/CXX11_shared_spin_lock.cpp
|
|
||||||
src/test/UDPC_UnitTest.cpp
|
src/test/UDPC_UnitTest.cpp
|
||||||
src/test/TestTSLQueue.cpp
|
src/test/TestTSLQueue.cpp
|
||||||
src/test/TestUDPC.cpp
|
src/test/TestUDPC.cpp
|
||||||
|
|
|
@ -1,218 +0,0 @@
|
||||||
#include "CXX11_shared_spin_lock.hpp"
|
|
||||||
|
|
||||||
UDPC::Badge UDPC::Badge::newInvalid() {
|
|
||||||
Badge badge;
|
|
||||||
badge.isValid = false;
|
|
||||||
return badge;
|
|
||||||
}
|
|
||||||
|
|
||||||
UDPC::Badge::Badge() :
|
|
||||||
isValid(true)
|
|
||||||
{}
|
|
||||||
|
|
||||||
UDPC::SharedSpinLock::Ptr UDPC::SharedSpinLock::newInstance() {
|
|
||||||
Ptr sharedSpinLock = Ptr(new SharedSpinLock());
|
|
||||||
sharedSpinLock->selfWeakPtr = sharedSpinLock;
|
|
||||||
return sharedSpinLock;
|
|
||||||
}
|
|
||||||
|
|
||||||
UDPC::SharedSpinLock::SharedSpinLock() :
|
|
||||||
selfWeakPtr(),
|
|
||||||
spinLock(false),
|
|
||||||
read(0),
|
|
||||||
write(false)
|
|
||||||
{}
|
|
||||||
|
|
||||||
UDPC::LockObj<false> UDPC::SharedSpinLock::spin_read_lock() {
|
|
||||||
bool expected;
|
|
||||||
while (true) {
|
|
||||||
expected = false;
|
|
||||||
if(spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire)) {
|
|
||||||
if (!write) {
|
|
||||||
++read;
|
|
||||||
spinLock.store(false, std::memory_order_release);
|
|
||||||
return LockObj<false>(selfWeakPtr, Badge{});
|
|
||||||
} else {
|
|
||||||
spinLock.store(false, std::memory_order_release);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UDPC::LockObj<false> UDPC::SharedSpinLock::try_spin_read_lock() {
|
|
||||||
bool expected;
|
|
||||||
while (true) {
|
|
||||||
expected = false;
|
|
||||||
if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire)) {
|
|
||||||
if (!write) {
|
|
||||||
++read;
|
|
||||||
spinLock.store(false, std::memory_order_release);
|
|
||||||
return LockObj<false>(selfWeakPtr, Badge{});
|
|
||||||
} else {
|
|
||||||
spinLock.store(false, std::memory_order_release);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return LockObj<false>{};
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDPC::SharedSpinLock::read_unlock(UDPC::Badge &&badge) {
|
|
||||||
if (badge.isValid) {
|
|
||||||
bool expected;
|
|
||||||
while (true) {
|
|
||||||
expected = false;
|
|
||||||
if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire)) {
|
|
||||||
if (read > 0) {
|
|
||||||
--read;
|
|
||||||
badge.isValid = false;
|
|
||||||
}
|
|
||||||
spinLock.store(false, std::memory_order_release);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UDPC::LockObj<true> UDPC::SharedSpinLock::spin_write_lock() {
|
|
||||||
bool expected;
|
|
||||||
while (true) {
|
|
||||||
expected = false;
|
|
||||||
if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire)) {
|
|
||||||
if (!write && read == 0) {
|
|
||||||
write = true;
|
|
||||||
spinLock.store(false, std::memory_order_release);
|
|
||||||
return LockObj<true>(selfWeakPtr, Badge{});
|
|
||||||
} else {
|
|
||||||
spinLock.store(false, std::memory_order_release);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UDPC::LockObj<true> UDPC::SharedSpinLock::try_spin_write_lock() {
|
|
||||||
bool expected;
|
|
||||||
while (true) {
|
|
||||||
expected = false;
|
|
||||||
if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire)) {
|
|
||||||
if (!write && read == 0) {
|
|
||||||
write = true;
|
|
||||||
spinLock.store(false, std::memory_order_release);
|
|
||||||
return LockObj<true>(selfWeakPtr, Badge{});
|
|
||||||
} else {
|
|
||||||
spinLock.store(false, std::memory_order_release);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return LockObj<true>{};
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDPC::SharedSpinLock::write_unlock(UDPC::Badge &&badge) {
|
|
||||||
if (badge.isValid) {
|
|
||||||
bool expected;
|
|
||||||
while(true) {
|
|
||||||
expected = false;
|
|
||||||
if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire)) {
|
|
||||||
if (write) {
|
|
||||||
write = false;
|
|
||||||
badge.isValid = false;
|
|
||||||
}
|
|
||||||
spinLock.store(false, std::memory_order_release);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UDPC::LockObj<false> UDPC::SharedSpinLock::trade_write_for_read_lock(UDPC::LockObj<true> &lockObj) {
|
|
||||||
if (lockObj.isValid() && lockObj.badge.isValid) {
|
|
||||||
bool expected;
|
|
||||||
while (true) {
|
|
||||||
expected = false;
|
|
||||||
if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire)) {
|
|
||||||
if (write && read == 0) {
|
|
||||||
read = 1;
|
|
||||||
write = false;
|
|
||||||
lockObj.isLocked = false;
|
|
||||||
lockObj.badge.isValid = false;
|
|
||||||
spinLock.store(false, std::memory_order_release);
|
|
||||||
return LockObj<false>(selfWeakPtr, Badge{});
|
|
||||||
} else {
|
|
||||||
spinLock.store(false, std::memory_order_release);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return LockObj<false>{};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UDPC::LockObj<false> UDPC::SharedSpinLock::try_trade_write_for_read_lock(UDPC::LockObj<true> &lockObj) {
|
|
||||||
if (lockObj.isValid() && lockObj.badge.isValid) {
|
|
||||||
bool expected;
|
|
||||||
while (true) {
|
|
||||||
expected = false;
|
|
||||||
if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire)) {
|
|
||||||
if (write && read == 0) {
|
|
||||||
read = 1;
|
|
||||||
write = false;
|
|
||||||
lockObj.isLocked = false;
|
|
||||||
lockObj.badge.isValid = false;
|
|
||||||
spinLock.store(false, std::memory_order_release);
|
|
||||||
return LockObj<false>(selfWeakPtr, Badge{});
|
|
||||||
} else {
|
|
||||||
spinLock.store(false, std::memory_order_release);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return LockObj<false>{};
|
|
||||||
}
|
|
||||||
|
|
||||||
UDPC::LockObj<true> UDPC::SharedSpinLock::trade_read_for_write_lock(UDPC::LockObj<false> &lockObj) {
|
|
||||||
if (lockObj.isValid() && lockObj.badge.isValid) {
|
|
||||||
bool expected;
|
|
||||||
while (true) {
|
|
||||||
expected = false;
|
|
||||||
if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire)) {
|
|
||||||
if (!write && read == 1) {
|
|
||||||
read = 0;
|
|
||||||
write = true;
|
|
||||||
lockObj.isLocked = false;
|
|
||||||
lockObj.badge.isValid = false;
|
|
||||||
spinLock.store(false, std::memory_order_release);
|
|
||||||
return LockObj<true>(selfWeakPtr, Badge{});
|
|
||||||
} else {
|
|
||||||
spinLock.store(false, std::memory_order_release);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return LockObj<true>{};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UDPC::LockObj<true> UDPC::SharedSpinLock::try_trade_read_for_write_lock(UDPC::LockObj<false> &lockObj) {
|
|
||||||
if (lockObj.isValid() && lockObj.badge.isValid) {
|
|
||||||
bool expected;
|
|
||||||
while (true) {
|
|
||||||
expected = false;
|
|
||||||
if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire)) {
|
|
||||||
if (!write && read == 1) {
|
|
||||||
read = 0;
|
|
||||||
write = true;
|
|
||||||
lockObj.isLocked = false;
|
|
||||||
lockObj.badge.isValid = false;
|
|
||||||
spinLock.store(false, std::memory_order_release);
|
|
||||||
return LockObj<true>(selfWeakPtr, Badge{});
|
|
||||||
} else {
|
|
||||||
spinLock.store(false, std::memory_order_release);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return LockObj<true>{};
|
|
||||||
}
|
|
|
@ -1,156 +0,0 @@
|
||||||
#ifndef UDPC_CXX11_SHARED_SPIN_LOCK_H_
|
|
||||||
#define UDPC_CXX11_SHARED_SPIN_LOCK_H_
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
namespace UDPC {
|
|
||||||
|
|
||||||
// Forward declaration for LockObj.
|
|
||||||
class SharedSpinLock;
|
|
||||||
|
|
||||||
class Badge {
|
|
||||||
public:
|
|
||||||
static Badge newInvalid();
|
|
||||||
|
|
||||||
// Disallow copy.
|
|
||||||
Badge(const Badge&) = delete;
|
|
||||||
Badge& operator=(const Badge&) = delete;
|
|
||||||
|
|
||||||
// Allow move.
|
|
||||||
Badge(Badge&&) = default;
|
|
||||||
Badge& operator=(Badge&&) = default;
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class SharedSpinLock;
|
|
||||||
|
|
||||||
// Can only be created by SharedSpinLock.
|
|
||||||
Badge();
|
|
||||||
|
|
||||||
bool isValid;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <bool IsWriteObj>
|
|
||||||
class LockObj {
|
|
||||||
public:
|
|
||||||
// Invalid instance constructor.
|
|
||||||
LockObj();
|
|
||||||
|
|
||||||
~LockObj();
|
|
||||||
|
|
||||||
// Explicit invalid instance constructor.
|
|
||||||
static LockObj<IsWriteObj> newInvalid();
|
|
||||||
|
|
||||||
// Disallow copy.
|
|
||||||
LockObj(const LockObj&) = delete;
|
|
||||||
LockObj& operator=(const LockObj&) = delete;
|
|
||||||
|
|
||||||
// Allow move.
|
|
||||||
LockObj(LockObj&&) = default;
|
|
||||||
LockObj& operator=(LockObj&&) = default;
|
|
||||||
|
|
||||||
bool isValid() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class SharedSpinLock;
|
|
||||||
|
|
||||||
// Only can be created by SharedSpinLock.
|
|
||||||
LockObj(Badge &&badge);
|
|
||||||
LockObj(std::weak_ptr<SharedSpinLock> lockPtr, Badge &&badge);
|
|
||||||
|
|
||||||
std::weak_ptr<SharedSpinLock> weakPtrLock;
|
|
||||||
bool isLocked;
|
|
||||||
Badge badge;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SharedSpinLock {
|
|
||||||
public:
|
|
||||||
using Ptr = std::shared_ptr<SharedSpinLock>;
|
|
||||||
using Weak = std::weak_ptr<SharedSpinLock>;
|
|
||||||
|
|
||||||
static Ptr newInstance();
|
|
||||||
|
|
||||||
// Disallow copy.
|
|
||||||
SharedSpinLock(const SharedSpinLock&) = delete;
|
|
||||||
SharedSpinLock& operator=(const SharedSpinLock&) = delete;
|
|
||||||
|
|
||||||
// Disallow move.
|
|
||||||
SharedSpinLock(SharedSpinLock&&) = delete;
|
|
||||||
SharedSpinLock& operator=(SharedSpinLock&&) = delete;
|
|
||||||
|
|
||||||
LockObj<false> spin_read_lock();
|
|
||||||
LockObj<false> try_spin_read_lock();
|
|
||||||
void read_unlock(Badge&&);
|
|
||||||
|
|
||||||
LockObj<true> spin_write_lock();
|
|
||||||
LockObj<true> try_spin_write_lock();
|
|
||||||
void write_unlock(Badge&&);
|
|
||||||
|
|
||||||
LockObj<false> trade_write_for_read_lock(LockObj<true>&);
|
|
||||||
LockObj<false> try_trade_write_for_read_lock(LockObj<true>&);
|
|
||||||
|
|
||||||
LockObj<true> trade_read_for_write_lock(LockObj<false>&);
|
|
||||||
LockObj<true> try_trade_read_for_write_lock(LockObj<false>&);
|
|
||||||
|
|
||||||
private:
|
|
||||||
SharedSpinLock();
|
|
||||||
|
|
||||||
Weak selfWeakPtr;
|
|
||||||
|
|
||||||
/// Used to lock the read/write member variables.
|
|
||||||
volatile std::atomic_bool spinLock;
|
|
||||||
|
|
||||||
unsigned int read;
|
|
||||||
bool write;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
template <bool IsWriteObj>
|
|
||||||
LockObj<IsWriteObj>::LockObj() :
|
|
||||||
weakPtrLock(),
|
|
||||||
isLocked(false),
|
|
||||||
badge(UDPC::Badge::newInvalid())
|
|
||||||
{}
|
|
||||||
|
|
||||||
template <bool IsWriteObj>
|
|
||||||
LockObj<IsWriteObj>::LockObj(Badge &&badge) :
|
|
||||||
weakPtrLock(),
|
|
||||||
isLocked(false),
|
|
||||||
badge(std::forward<Badge>(badge))
|
|
||||||
{}
|
|
||||||
|
|
||||||
template <bool IsWriteObj>
|
|
||||||
LockObj<IsWriteObj>::LockObj(SharedSpinLock::Weak lockPtr, Badge &&badge) :
|
|
||||||
weakPtrLock(lockPtr),
|
|
||||||
isLocked(true),
|
|
||||||
badge(std::forward<Badge>(badge))
|
|
||||||
{}
|
|
||||||
|
|
||||||
template <bool IsWriteObj>
|
|
||||||
LockObj<IsWriteObj>::~LockObj() {
|
|
||||||
if (!isLocked) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto strongPtrLock = weakPtrLock.lock();
|
|
||||||
if (strongPtrLock) {
|
|
||||||
if (IsWriteObj) {
|
|
||||||
strongPtrLock->write_unlock(std::move(badge));
|
|
||||||
} else {
|
|
||||||
strongPtrLock->read_unlock(std::move(badge));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <bool IsWriteObj>
|
|
||||||
LockObj<IsWriteObj> LockObj<IsWriteObj>::newInvalid() {
|
|
||||||
return LockObj<IsWriteObj>{};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <bool IsWriteObj>
|
|
||||||
bool LockObj<IsWriteObj>::isValid() const {
|
|
||||||
return isLocked;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace UDPC
|
|
||||||
|
|
||||||
#endif
|
|
122
src/TSLQueue.hpp
122
src/TSLQueue.hpp
|
@ -2,6 +2,7 @@
|
||||||
#define UDPC_THREADSAFE_LINKEDLIST_QUEUE_HPP
|
#define UDPC_THREADSAFE_LINKEDLIST_QUEUE_HPP
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
@ -9,8 +10,6 @@
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
#include "CXX11_shared_spin_lock.hpp"
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class TSLQueue {
|
class TSLQueue {
|
||||||
public:
|
public:
|
||||||
|
@ -63,7 +62,7 @@ class TSLQueue {
|
||||||
|
|
||||||
class TSLQIter {
|
class TSLQIter {
|
||||||
public:
|
public:
|
||||||
TSLQIter(UDPC::SharedSpinLock::Weak sharedSpinLockWeak,
|
TSLQIter(std::mutex *mutex,
|
||||||
std::weak_ptr<TSLQNode> currentNode,
|
std::weak_ptr<TSLQNode> currentNode,
|
||||||
unsigned long *msize);
|
unsigned long *msize);
|
||||||
~TSLQIter();
|
~TSLQIter();
|
||||||
|
@ -76,24 +75,19 @@ class TSLQueue {
|
||||||
bool next();
|
bool next();
|
||||||
bool prev();
|
bool prev();
|
||||||
bool remove();
|
bool remove();
|
||||||
bool try_remove();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UDPC::SharedSpinLock::Weak sharedSpinLockWeak;
|
std::mutex *mutex;
|
||||||
std::unique_ptr<UDPC::LockObj<false>> readLock;
|
|
||||||
std::unique_ptr<UDPC::LockObj<true>> writeLock;
|
|
||||||
std::weak_ptr<TSLQNode> currentNode;
|
std::weak_ptr<TSLQNode> currentNode;
|
||||||
unsigned long *const msize;
|
unsigned long *const msize;
|
||||||
|
|
||||||
bool remove_impl();
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TSLQIter begin();
|
TSLQIter begin();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UDPC::SharedSpinLock::Ptr sharedSpinLock;
|
std::mutex mutex;
|
||||||
std::shared_ptr<TSLQNode> head;
|
std::shared_ptr<TSLQNode> head;
|
||||||
std::shared_ptr<TSLQNode> tail;
|
std::shared_ptr<TSLQNode> tail;
|
||||||
unsigned long msize;
|
unsigned long msize;
|
||||||
|
@ -101,7 +95,7 @@ class TSLQueue {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
TSLQueue<T>::TSLQueue() :
|
TSLQueue<T>::TSLQueue() :
|
||||||
sharedSpinLock(UDPC::SharedSpinLock::newInstance()),
|
mutex(),
|
||||||
head(std::shared_ptr<TSLQNode>(new TSLQNode())),
|
head(std::shared_ptr<TSLQNode>(new TSLQNode())),
|
||||||
tail(std::shared_ptr<TSLQNode>(new TSLQNode())),
|
tail(std::shared_ptr<TSLQNode>(new TSLQNode())),
|
||||||
msize(0)
|
msize(0)
|
||||||
|
@ -117,14 +111,9 @@ TSLQueue<T>::~TSLQueue() {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
TSLQueue<T>::TSLQueue(TSLQueue &&other) :
|
TSLQueue<T>::TSLQueue(TSLQueue &&other)
|
||||||
sharedSpinLock(UDPC::SharedSpinLock::newInstance()),
|
|
||||||
head(std::shared_ptr<TSLQNode>(new TSLQNode())),
|
|
||||||
tail(std::shared_ptr<TSLQNode>(new TSLQNode())),
|
|
||||||
msize(0)
|
|
||||||
{
|
{
|
||||||
auto selfWriteLock = sharedSpinLock->spin_write_lock();
|
std::lock_guard<std::mutex> lock(other.mutex);
|
||||||
auto otherWriteLock = other.sharedSpinLock->spin_write_lock();
|
|
||||||
head = std::move(other.head);
|
head = std::move(other.head);
|
||||||
tail = std::move(other.tail);
|
tail = std::move(other.tail);
|
||||||
msize = std::move(other.msize);
|
msize = std::move(other.msize);
|
||||||
|
@ -132,8 +121,8 @@ TSLQueue<T>::TSLQueue(TSLQueue &&other) :
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
TSLQueue<T> & TSLQueue<T>::operator=(TSLQueue &&other) {
|
TSLQueue<T> & TSLQueue<T>::operator=(TSLQueue &&other) {
|
||||||
auto selfWriteLock = sharedSpinLock->spin_write_lock();
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
auto otherWriteLock = other.sharedSpinLock->spin_write_lock();
|
std::lock_guard<std::mutex> otherLock(other.mutex);
|
||||||
head = std::move(other.head);
|
head = std::move(other.head);
|
||||||
tail = std::move(other.tail);
|
tail = std::move(other.tail);
|
||||||
msize = std::move(other.msize);
|
msize = std::move(other.msize);
|
||||||
|
@ -141,7 +130,7 @@ TSLQueue<T> & TSLQueue<T>::operator=(TSLQueue &&other) {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void TSLQueue<T>::push(const T &data) {
|
void TSLQueue<T>::push(const T &data) {
|
||||||
auto writeLock = sharedSpinLock->spin_write_lock();
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
auto newNode = std::shared_ptr<TSLQNode>(new TSLQNode());
|
auto newNode = std::shared_ptr<TSLQNode>(new TSLQNode());
|
||||||
newNode->data = std::unique_ptr<T>(new T(data));
|
newNode->data = std::unique_ptr<T>(new T(data));
|
||||||
|
|
||||||
|
@ -157,8 +146,7 @@ void TSLQueue<T>::push(const T &data) {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool TSLQueue<T>::push_nb(const T &data) {
|
bool TSLQueue<T>::push_nb(const T &data) {
|
||||||
auto writeLock = sharedSpinLock->try_spin_write_lock();
|
if(mutex.try_lock()) {
|
||||||
if(writeLock.isValid()) {
|
|
||||||
auto newNode = std::shared_ptr<TSLQNode>(new TSLQNode());
|
auto newNode = std::shared_ptr<TSLQNode>(new TSLQNode());
|
||||||
newNode->data = std::unique_ptr<T>(new T(data));
|
newNode->data = std::unique_ptr<T>(new T(data));
|
||||||
|
|
||||||
|
@ -171,6 +159,7 @@ bool TSLQueue<T>::push_nb(const T &data) {
|
||||||
tail->prev = newNode;
|
tail->prev = newNode;
|
||||||
++msize;
|
++msize;
|
||||||
|
|
||||||
|
mutex.unlock();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -179,7 +168,7 @@ bool TSLQueue<T>::push_nb(const T &data) {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::unique_ptr<T> TSLQueue<T>::top() {
|
std::unique_ptr<T> TSLQueue<T>::top() {
|
||||||
auto readLock = sharedSpinLock->spin_read_lock();
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
std::unique_ptr<T> result;
|
std::unique_ptr<T> result;
|
||||||
if(head->next != tail) {
|
if(head->next != tail) {
|
||||||
assert(head->next->data);
|
assert(head->next->data);
|
||||||
|
@ -192,20 +181,20 @@ std::unique_ptr<T> TSLQueue<T>::top() {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::unique_ptr<T> TSLQueue<T>::top_nb() {
|
std::unique_ptr<T> TSLQueue<T>::top_nb() {
|
||||||
std::unique_ptr<T> result;
|
std::unique_ptr<T> result;
|
||||||
auto readLock = sharedSpinLock->try_spin_read_lock();
|
if(mutex.try_lock()) {
|
||||||
if(readLock.isValid()) {
|
|
||||||
if(head->next != tail) {
|
if(head->next != tail) {
|
||||||
assert(head->next->data);
|
assert(head->next->data);
|
||||||
result = std::unique_ptr<T>(new T);
|
result = std::unique_ptr<T>(new T);
|
||||||
*result = *head->next->data;
|
*result = *head->next->data;
|
||||||
}
|
}
|
||||||
|
mutex.unlock();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool TSLQueue<T>::pop() {
|
bool TSLQueue<T>::pop() {
|
||||||
auto writeLock = sharedSpinLock->spin_write_lock();
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
if(head->next == tail) {
|
if(head->next == tail) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -222,7 +211,7 @@ bool TSLQueue<T>::pop() {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::unique_ptr<T> TSLQueue<T>::top_and_pop() {
|
std::unique_ptr<T> TSLQueue<T>::top_and_pop() {
|
||||||
std::unique_ptr<T> result;
|
std::unique_ptr<T> result;
|
||||||
auto writeLock = sharedSpinLock->spin_write_lock();
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
if(head->next != tail) {
|
if(head->next != tail) {
|
||||||
assert(head->next->data);
|
assert(head->next->data);
|
||||||
result = std::unique_ptr<T>(new T);
|
result = std::unique_ptr<T>(new T);
|
||||||
|
@ -240,7 +229,7 @@ std::unique_ptr<T> TSLQueue<T>::top_and_pop() {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::unique_ptr<T> TSLQueue<T>::top_and_pop_and_empty(bool *isEmpty) {
|
std::unique_ptr<T> TSLQueue<T>::top_and_pop_and_empty(bool *isEmpty) {
|
||||||
std::unique_ptr<T> result;
|
std::unique_ptr<T> result;
|
||||||
auto writeLock = sharedSpinLock->spin_write_lock();
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
if(head->next == tail) {
|
if(head->next == tail) {
|
||||||
if(isEmpty) {
|
if(isEmpty) {
|
||||||
*isEmpty = true;
|
*isEmpty = true;
|
||||||
|
@ -266,7 +255,7 @@ std::unique_ptr<T> TSLQueue<T>::top_and_pop_and_empty(bool *isEmpty) {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::unique_ptr<T> TSLQueue<T>::top_and_pop_and_rsize(unsigned long *rsize) {
|
std::unique_ptr<T> TSLQueue<T>::top_and_pop_and_rsize(unsigned long *rsize) {
|
||||||
std::unique_ptr<T> result;
|
std::unique_ptr<T> result;
|
||||||
auto writeLock = sharedSpinLock->spin_write_lock();
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
if(head->next == tail) {
|
if(head->next == tail) {
|
||||||
if(rsize) {
|
if(rsize) {
|
||||||
*rsize = 0;
|
*rsize = 0;
|
||||||
|
@ -291,7 +280,7 @@ std::unique_ptr<T> TSLQueue<T>::top_and_pop_and_rsize(unsigned long *rsize) {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void TSLQueue<T>::clear() {
|
void TSLQueue<T>::clear() {
|
||||||
auto writeLock = sharedSpinLock->spin_write_lock();
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
|
||||||
head->next = tail;
|
head->next = tail;
|
||||||
tail->prev = head;
|
tail->prev = head;
|
||||||
|
@ -300,13 +289,13 @@ void TSLQueue<T>::clear() {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool TSLQueue<T>::empty() {
|
bool TSLQueue<T>::empty() {
|
||||||
auto readLock = sharedSpinLock->spin_read_lock();
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
return head->next == tail;
|
return head->next == tail;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
unsigned long TSLQueue<T>::size() {
|
unsigned long TSLQueue<T>::size() {
|
||||||
auto readLock = sharedSpinLock->spin_read_lock();
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
return msize;
|
return msize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,20 +313,20 @@ bool TSLQueue<T>::TSLQNode::isNormal() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
TSLQueue<T>::TSLQIter::TSLQIter(UDPC::SharedSpinLock::Weak lockWeak,
|
TSLQueue<T>::TSLQIter::TSLQIter(std::mutex *mutex,
|
||||||
std::weak_ptr<TSLQNode> currentNode,
|
std::weak_ptr<TSLQNode> currentNode,
|
||||||
unsigned long *msize) :
|
unsigned long *msize) :
|
||||||
sharedSpinLockWeak(lockWeak),
|
mutex(mutex),
|
||||||
readLock(std::unique_ptr<UDPC::LockObj<false>>(new UDPC::LockObj<false>{})),
|
|
||||||
writeLock(),
|
|
||||||
currentNode(currentNode),
|
currentNode(currentNode),
|
||||||
msize(msize)
|
msize(msize)
|
||||||
{
|
{
|
||||||
*readLock = lockWeak.lock()->spin_read_lock();
|
mutex->lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
TSLQueue<T>::TSLQIter::~TSLQIter() {}
|
TSLQueue<T>::TSLQIter::~TSLQIter() {
|
||||||
|
mutex->unlock();
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::unique_ptr<T> TSLQueue<T>::TSLQIter::current() {
|
std::unique_ptr<T> TSLQueue<T>::TSLQIter::current() {
|
||||||
|
@ -379,61 +368,9 @@ bool TSLQueue<T>::TSLQIter::prev() {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool TSLQueue<T>::TSLQIter::remove() {
|
bool TSLQueue<T>::TSLQIter::remove() {
|
||||||
if (readLock && !writeLock && readLock->isValid()) {
|
|
||||||
auto sharedSpinLockStrong = sharedSpinLockWeak.lock();
|
|
||||||
if (!sharedSpinLockStrong) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
writeLock = std::unique_ptr<UDPC::LockObj<true>>(new UDPC::LockObj<true>{});
|
|
||||||
*writeLock = sharedSpinLockStrong->trade_read_for_write_lock(*readLock);
|
|
||||||
readLock.reset(nullptr);
|
|
||||||
|
|
||||||
return remove_impl();
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
bool TSLQueue<T>::TSLQIter::try_remove() {
|
|
||||||
if (readLock && !writeLock && readLock->isValid()) {
|
|
||||||
auto sharedSpinLockStrong = sharedSpinLockWeak.lock();
|
|
||||||
if (!sharedSpinLockStrong) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
writeLock = std::unique_ptr<UDPC::LockObj<true>>(new UDPC::LockObj<true>{});
|
|
||||||
*writeLock = sharedSpinLockStrong->try_trade_read_for_write_lock(*readLock);
|
|
||||||
if (writeLock->isValid()) {
|
|
||||||
readLock.reset(nullptr);
|
|
||||||
return remove_impl();
|
|
||||||
} else {
|
|
||||||
writeLock.reset(nullptr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
bool TSLQueue<T>::TSLQIter::remove_impl() {
|
|
||||||
const auto cleanupWriteLock = [this] () {
|
|
||||||
UDPC::SharedSpinLock::Ptr sharedSpinLockStrong = this->sharedSpinLockWeak.lock();
|
|
||||||
if (!sharedSpinLockStrong) {
|
|
||||||
writeLock.reset(nullptr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this->readLock = std::unique_ptr<UDPC::LockObj<false>>(new UDPC::LockObj<false>{});
|
|
||||||
(*this->readLock) = sharedSpinLockStrong->trade_write_for_read_lock(*(this->writeLock));
|
|
||||||
this->writeLock.reset(nullptr);
|
|
||||||
};
|
|
||||||
|
|
||||||
std::shared_ptr<TSLQNode> currentNode = this->currentNode.lock();
|
std::shared_ptr<TSLQNode> currentNode = this->currentNode.lock();
|
||||||
assert(currentNode);
|
assert(currentNode);
|
||||||
if(!currentNode->isNormal()) {
|
if(!currentNode->isNormal()) {
|
||||||
cleanupWriteLock();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,13 +384,12 @@ bool TSLQueue<T>::TSLQIter::remove_impl() {
|
||||||
assert(*msize > 0);
|
assert(*msize > 0);
|
||||||
--(*msize);
|
--(*msize);
|
||||||
|
|
||||||
cleanupWriteLock();
|
|
||||||
return parent->next->isNormal();
|
return parent->next->isNormal();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename TSLQueue<T>::TSLQIter TSLQueue<T>::begin() {
|
typename TSLQueue<T>::TSLQIter TSLQueue<T>::begin() {
|
||||||
return TSLQIter(sharedSpinLock, head->next, &msize);
|
return TSLQIter(&mutex, head->next, &msize);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -143,8 +143,7 @@ TEST(TSLQueue, Iterator) {
|
||||||
// test that lock is held by iterator
|
// test that lock is held by iterator
|
||||||
EXPECT_FALSE(q.push_nb(10));
|
EXPECT_FALSE(q.push_nb(10));
|
||||||
op = q.top_nb();
|
op = q.top_nb();
|
||||||
// Getting top and iterator both hold read locks so this should be true.
|
EXPECT_FALSE(op);
|
||||||
EXPECT_TRUE(op);
|
|
||||||
|
|
||||||
// backwards iteration
|
// backwards iteration
|
||||||
EXPECT_TRUE(iter.prev());
|
EXPECT_TRUE(iter.prev());
|
||||||
|
@ -176,21 +175,6 @@ TEST(TSLQueue, Iterator) {
|
||||||
op = iter.current();
|
op = iter.current();
|
||||||
EXPECT_TRUE(op);
|
EXPECT_TRUE(op);
|
||||||
EXPECT_EQ(*op, 2);
|
EXPECT_EQ(*op, 2);
|
||||||
|
|
||||||
// second iterator
|
|
||||||
auto iter2 = q.begin();
|
|
||||||
|
|
||||||
// Still should be able to get top.
|
|
||||||
EXPECT_TRUE(iter2.current());
|
|
||||||
|
|
||||||
// Shouldn't be able to remove if 2 iterators exist.
|
|
||||||
EXPECT_FALSE(iter2.try_remove());
|
|
||||||
|
|
||||||
// This will never return since the first iterator has a "read" lock.
|
|
||||||
//EXPECT_FALSE(iter2.remove());
|
|
||||||
|
|
||||||
// Still should be able to get top.
|
|
||||||
EXPECT_TRUE(iter2.current());
|
|
||||||
}
|
}
|
||||||
EXPECT_EQ(q.size(), 9);
|
EXPECT_EQ(q.size(), 9);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue