diff options
author | Anton Samokhvalov <pg83@yandex.ru> | 2022-02-10 16:45:15 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:15 +0300 |
commit | 72cb13b4aff9bc9cf22e49251bc8fd143f82538f (patch) | |
tree | da2c34829458c7d4e74bdfbdf85dff449e9e7fb8 /util/thread/lfstack.h | |
parent | 778e51ba091dc39e7b7fcab2b9cf4dbedfb6f2b5 (diff) | |
download | ydb-72cb13b4aff9bc9cf22e49251bc8fd143f82538f.tar.gz |
Restoring authorship annotation for Anton Samokhvalov <pg83@yandex.ru>. Commit 1 of 2.
Diffstat (limited to 'util/thread/lfstack.h')
-rw-r--r-- | util/thread/lfstack.h | 66 |
1 files changed, 33 insertions, 33 deletions
diff --git a/util/thread/lfstack.h b/util/thread/lfstack.h index ca3d95f3c3..aa64ce1dbe 100644 --- a/util/thread/lfstack.h +++ b/util/thread/lfstack.h @@ -5,31 +5,31 @@ ////////////////////////////// // lock free lifo stack -template <class T> -class TLockFreeStack: TNonCopyable { - struct TNode { +template <class T> +class TLockFreeStack: TNonCopyable { + struct TNode { T Value; - TNode* Next; + TNode* Next; TNode() = default; - template <class U> + template <class U> explicit TNode(U&& val) : Value(std::forward<U>(val)) , Next(nullptr) - { - } + { + } }; TNode* Head; TNode* FreePtr; TAtomic DequeueCount; - void TryToFreeMemory() { + void TryToFreeMemory() { TNode* current = AtomicGet(FreePtr); if (!current) return; - if (AtomicAdd(DequeueCount, 0) == 1) { + if (AtomicAdd(DequeueCount, 0) == 1) { // node current is in free list, we are the last thread so try to cleanup if (AtomicCas(&FreePtr, (TNode*)nullptr, current)) EraseList(current); @@ -37,7 +37,7 @@ class TLockFreeStack: TNonCopyable { } void EraseList(TNode* volatile p) { while (p) { - TNode* next = p->Next; + TNode* next = p->Next; delete p; p = next; } @@ -54,20 +54,20 @@ class TLockFreeStack: TNonCopyable { TNode* volatile node = new TNode(std::forward<U>(u)); EnqueueImpl(node, node); } - + public: - TLockFreeStack() + TLockFreeStack() : Head(nullptr) , FreePtr(nullptr) - , DequeueCount(0) - { - } - ~TLockFreeStack() { + , DequeueCount(0) + { + } + ~TLockFreeStack() { EraseList(Head); EraseList(FreePtr); } - void Enqueue(const T& t) { + void Enqueue(const T& t) { EnqueueImpl(t); } @@ -76,11 +76,11 @@ public: } template <typename TCollection> - void EnqueueAll(const TCollection& data) { + void EnqueueAll(const TCollection& data) { EnqueueAll(data.begin(), data.end()); } template <typename TIter> - void EnqueueAll(TIter dataBegin, TIter dataEnd) { + void EnqueueAll(TIter dataBegin, TIter dataEnd) { if (dataBegin == dataEnd) { return; } @@ -95,22 +95,22 @@ public: } EnqueueImpl(node, tail); } - bool Dequeue(T* res) { - AtomicAdd(DequeueCount, 1); + bool Dequeue(T* res) { + AtomicAdd(DequeueCount, 1); for (TNode* current = AtomicGet(Head); current; current = AtomicGet(Head)) { if (AtomicCas(&Head, AtomicGet(current->Next), current)) { *res = std::move(current->Value); // delete current; // ABA problem // even more complex node deletion TryToFreeMemory(); - if (AtomicAdd(DequeueCount, -1) == 0) { + if (AtomicAdd(DequeueCount, -1) == 0) { // no other Dequeue()s, can safely reclaim memory delete current; } else { // Dequeue()s in progress, put node to free list - for (;;) { + for (;;) { AtomicSet(current->Next, AtomicGet(FreePtr)); - if (AtomicCas(&FreePtr, current, current->Next)) + if (AtomicCas(&FreePtr, current, current->Next)) break; } } @@ -118,17 +118,17 @@ public: } } TryToFreeMemory(); - AtomicAdd(DequeueCount, -1); + AtomicAdd(DequeueCount, -1); return false; } // add all elements to *res // elements are returned in order of dequeue (top to bottom; see example in unittest) template <typename TCollection> - void DequeueAll(TCollection* res) { + void DequeueAll(TCollection* res) { AtomicAdd(DequeueCount, 1); for (TNode* current = AtomicGet(Head); current; current = AtomicGet(Head)) { if (AtomicCas(&Head, (TNode*)nullptr, current)) { - for (TNode* x = current; x;) { + for (TNode* x = current; x;) { res->push_back(std::move(x->Value)); x = x->Next; } @@ -140,9 +140,9 @@ public: EraseList(current); } else { // Dequeue()s in progress, add nodes list to free list - TNode* currentLast = current; + TNode* currentLast = current; while (currentLast->Next) { - currentLast = currentLast->Next; + currentLast = currentLast->Next; } for (;;) { AtomicSet(currentLast->Next, AtomicGet(FreePtr)); @@ -156,7 +156,7 @@ public: TryToFreeMemory(); AtomicAdd(DequeueCount, -1); } - bool DequeueSingleConsumer(T* res) { + bool DequeueSingleConsumer(T* res) { for (TNode* current = AtomicGet(Head); current; current = AtomicGet(Head)) { if (AtomicCas(&Head, current->Next, current)) { *res = std::move(current->Value); @@ -169,10 +169,10 @@ public: // add all elements to *res // elements are returned in order of dequeue (top to bottom; see example in unittest) template <typename TCollection> - void DequeueAllSingleConsumer(TCollection* res) { + void DequeueAllSingleConsumer(TCollection* res) { for (TNode* current = AtomicGet(Head); current; current = AtomicGet(Head)) { if (AtomicCas(&Head, (TNode*)nullptr, current)) { - for (TNode* x = current; x;) { + for (TNode* x = current; x;) { res->push_back(std::move(x->Value)); x = x->Next; } @@ -181,7 +181,7 @@ public: } } } - bool IsEmpty() { + bool IsEmpty() { AtomicAdd(DequeueCount, 0); // mem barrier return AtomicGet(Head) == nullptr; // without lock, so result is approximate } |