diff options
author | Jean-Francois Mauguit <jfmauguit@mac.com> | 2024-09-24 09:03:25 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-24 09:03:25 -0400 |
commit | bab614c421ed7ae329d26bf028c4a3b1d2450f5a (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/nu/LockFreeStack.h | |
parent | 4bde6044fddf053f31795b9eaccdd2a5a527d21f (diff) | |
parent | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (diff) | |
download | winamp-bab614c421ed7ae329d26bf028c4a3b1d2450f5a.tar.gz |
Merge pull request #5 from WinampDesktop/community
Merge to main
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 |