diff options
author | Pixel <pixel@nobis-crew.org> | 2009-11-12 00:35:43 -0800 |
---|---|---|
committer | Pixel <pixel@nobis-crew.org> | 2009-11-12 00:35:43 -0800 |
commit | a183b6355e22b4d701da4ae5e3243c3ebdeeb1e8 (patch) | |
tree | 7507075b1facffeabbbc422352519b1537728a95 | |
parent | d0110ebfd26a76d85d465b2cbc2332359dcf55e0 (diff) |
Adding atomic queues.
-rw-r--r-- | include/Atomic.h | 69 |
1 files changed, 68 insertions, 1 deletions
diff --git a/include/Atomic.h b/include/Atomic.h index 35edbf1..3b325f2 100644 --- a/include/Atomic.h +++ b/include/Atomic.h @@ -21,7 +21,8 @@ template <class T> T Increment(volatile T * ptr, T delta = 1) { __sync_fetch_and template <class T> T Decrement(volatile T * ptr, T delta = 1) { __sync_fetch_and_sub(ptr, delta); } }; -template <class T> T CmpXChg(volatile T * ptr, T xch, T cmp) { return __sync_val_compare_and_swap(ptr, cmp, xch); } +template <class T> T CmpXChgVal(volatile T * ptr, T xch, T cmp) { return __sync_val_compare_and_swap(ptr, cmp, xch); } +template <class T> bool CmpXChgBool(volatile T * ptr, T xch, T cmp) { return __sync_bool_compare_and_swap(ptr, cmp, xch); } template <class T> T Exchange32(volatile T * ptr, T exchange) { #if defined(i386) || defined (__x86_64) @@ -64,6 +65,72 @@ template <class T> T * ExchangePtr(T * volatile * ptr, T * exchange) { #endif } +// Based on "Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms" +template <class T> +class Queue { + public: + Queue() : Head(new node_t()), Tail(Head) { } + void enqueue(const T & val) { + node_t * node = new node_t(val); + ptr_t tail, next; + while(true) { + tail = Tail; + next = tail.ptr->next; + if (tail == Tail) { + if (next.ptr == NULL) { + ptr_t new_ptr(node, next.count + 1); + if (CmpXChgBool(&tail.ptr->next, new_ptr, next)) + break; + } else { + ptr_t new_ptr(next.ptr, tail.count + 1); + CmpXChgBool(&Tail, new_ptr, tail); + } + } + } + ptr_t new_ptr(node, tail.count + 1); + CmpXChgBool(&Tail, new_ptr, tail); + } + bool dequeue(T * pval) { + ptr_t head, tail, next; + while(true) { + head = Head; + tail = Tail; + next = head->next; + if (head == Head) { + if (head.ptr == tail.ptr) { + if (next.ptr == NULL) + return false; + ptr_t new_ptr(next.ptr, tail.count + 1); + CmpXChgBool(&Tail, new_ptr, tail); + } else { + *pval = next.ptr->value; + ptr_t new_ptr(next.ptr, head.count + 1); + if (CmpXChgBool(&Head, new_ptr, head)) + break; + } + } + } + delete head.ptr; + return true; + } + private: + struct node_t; + struct ptr_t { + ptr_t() : ptr(NULL), count(0) { } + ptr_t(node_t * ptr, unsigned int count = 0) : ptr(ptr), count(count) { } + ptr_t(const ptr_t & c) : ptr(c.ptr), count(c.count) { } + node_t * ptr; + unsigned int count; + }; + struct node_t { + node_t() { } + node_t(const T & val) : val(val) { } + T val; + ptr_t next; + }; + ptr_t Head, Tail; +}; + }; #endif |