From 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d Mon Sep 17 00:00:00 2001 From: Jef Date: Tue, 24 Sep 2024 14:54:57 +0200 Subject: Initial community commit --- Src/nu/LockFreeStack.h | 156 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 Src/nu/LockFreeStack.h (limited to 'Src/nu/LockFreeStack.h') diff --git a/Src/nu/LockFreeStack.h b/Src/nu/LockFreeStack.h new file mode 100644 index 00000000..7c1d1b1e --- /dev/null +++ b/Src/nu/LockFreeStack.h @@ -0,0 +1,156 @@ +#pragma once +#include + +/* lock free stack object +multiple threads can push and pop without locking +note that order is not guaranteed. that is, if Thread 1 calls Insert before Thread 2, Thread 2's item might still make it in before. + +since it uses malloc/free for the linked list nodes, it might not be considered truely lock-free. + +use LockFreeStack2 if you can assure that you have a 'next' pointer in your class/struct +*/ +template +class LockFreeStackNode +{ +public: + LockFreeStackNode(value_t _data) + { + data = _data; + next = 0; + } + value_t data; + + LockFreeStackNode *next; +}; + +template +class LockFreeStack +{ +public: + LockFreeStack() + { + head = 0; + } + + void push(value_t data) + { + LockFreeStackNode *new_head = new LockFreeStackNode(data); + LockFreeStackNode *old_head = 0; + do + { + old_head = (LockFreeStackNode *)head; + new_head->next = old_head; + } while (InterlockedCompareExchangePointer((volatile PVOID *)&head, new_head, old_head) != old_head); + } + + value_t pop() + { + LockFreeStackNode *new_head = 0, *old_head = 0; + do + { + old_head = (LockFreeStackNode *)head; + if (old_head) + { + new_head = old_head->next; + } + else + { + new_head = 0; + } + } while (InterlockedCompareExchangePointer((volatile PVOID *)&head, new_head, old_head) != old_head); + value_t ret = old_head?old_head->data:0; + delete old_head; + return ret; + } + + bool pop_ref(value_t *val) + { + LockFreeStackNode *new_head = 0, *old_head = 0; + do + { + old_head = (LockFreeStackNode *)head; + if (old_head) + { + new_head = old_head->next; + } + else + { + new_head = 0; + } + } while (InterlockedCompareExchangePointer((volatile PVOID *)&head, new_head, old_head) != old_head); + if (old_head) + { + *val = old_head->data; + delete old_head; + return true; + } + + return false; + } + + volatile LockFreeStackNode *head; +}; + +template +class LockFreeStack2 +{ +public: + LockFreeStack() + { + head = 0; + } + + void push(value_t *data) + { + value_t *old_head = 0; + do + { + old_head = head; + data->next = old_head; + } while (InterlockedCompareExchangePointer((volatile PVOID *)&head, data, old_head) != old_head); + } + + value_t *pop() + { + value_t *new_head = 0, *old_head = 0; + do + { + old_head = head; + if (old_head) + { + new_head = old_head->next; + } + else + { + new_head = 0; + } + } while (InterlockedCompareExchangePointer((volatile PVOID *)&head, new_head, old_head) != old_head); + return old_head; + } + + bool pop_ref(value_t **val) + { + value_t *new_head = 0, *old_head = 0; + do + { + old_head = head; + if (old_head) + { + new_head = old_head->next; + } + else + { + new_head = 0; + } + } while (InterlockedCompareExchangePointer((volatile PVOID *)&head, new_head, old_head) != old_head); + if (old_head) + { + *val = old_head; + return true; + } + + return false; + } + + volatile value_t *head; +}; \ No newline at end of file -- cgit