diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/nu/LockFreeStack.h | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/nu/LockFreeStack.h')
-rw-r--r-- | Src/nu/LockFreeStack.h | 156 |
1 files changed, 156 insertions, 0 deletions
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 <windows.h> + +/* 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 value_t> +class LockFreeStackNode +{ +public: + LockFreeStackNode(value_t _data) + { + data = _data; + next = 0; + } + value_t data; + + LockFreeStackNode *next; +}; + +template <class value_t> +class LockFreeStack +{ +public: + LockFreeStack() + { + head = 0; + } + + void push(value_t data) + { + LockFreeStackNode<value_t> *new_head = new LockFreeStackNode<value_t>(data); + LockFreeStackNode<value_t> *old_head = 0; + do + { + old_head = (LockFreeStackNode<value_t> *)head; + new_head->next = old_head; + } while (InterlockedCompareExchangePointer((volatile PVOID *)&head, new_head, old_head) != old_head); + } + + value_t pop() + { + LockFreeStackNode<value_t> *new_head = 0, *old_head = 0; + do + { + old_head = (LockFreeStackNode<value_t> *)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<value_t> *new_head = 0, *old_head = 0; + do + { + old_head = (LockFreeStackNode<value_t> *)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<value_t> *head; +}; + +template <class value_t> +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 |