Mercurial > pub > ImplabNet
comparison Implab/Parallels/MTCustomQueue.cs @ 106:d4e38929ce36 v2
promises refactoring
| author | cin |
|---|---|
| date | Mon, 10 Nov 2014 18:00:28 +0300 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 105:4d308952fd5e | 106:d4e38929ce36 |
|---|---|
| 1 using System; | |
| 2 using System.Collections.Generic; | |
| 3 using System.Threading; | |
| 4 using System.Collections; | |
| 5 | |
| 6 namespace Implab.Parallels { | |
| 7 public class MTCustomQueue<TNode> : IEnumerable<TNode> where TNode : MTCustomQueueNode<TNode> { | |
| 8 TNode m_first; | |
| 9 TNode m_last; | |
| 10 | |
| 11 public void Enqueue(TNode next) { | |
| 12 Thread.MemoryBarrier(); | |
| 13 | |
| 14 var last = m_last; | |
| 15 | |
| 16 // Interlocaked.CompareExchange implies Thread.MemoryBarrier(); | |
| 17 // to ensure that the next node is completely constructed | |
| 18 while (last != Interlocked.CompareExchange(ref m_last, next, last)) | |
| 19 last = m_last; | |
| 20 | |
| 21 if (last != null) | |
| 22 last.next = next; | |
| 23 else | |
| 24 m_first = next; | |
| 25 } | |
| 26 | |
| 27 public bool TryDequeue(out TNode node) { | |
| 28 TNode first; | |
| 29 TNode next; | |
| 30 node = null; | |
| 31 | |
| 32 Thread.MemoryBarrier(); | |
| 33 do { | |
| 34 first = m_first; | |
| 35 if (first == null) | |
| 36 return false; | |
| 37 next = first.next; | |
| 38 if (next == null) { | |
| 39 // this is the last element, | |
| 40 // then try to update the tail | |
| 41 if (first != Interlocked.CompareExchange(ref m_last, null, first)) { | |
| 42 // this is the race condition | |
| 43 if (m_last == null) | |
| 44 // the queue is empty | |
| 45 return false; | |
| 46 // tail has been changed, we need to restart | |
| 47 continue; | |
| 48 } | |
| 49 | |
| 50 // tail succesfully updated and first.next will never be changed | |
| 51 // other readers will fail due to inconsistency m_last != m_fist && m_first.next == null | |
| 52 // however the parallel writer may update the m_first since the m_last is null | |
| 53 | |
| 54 // so we need to fix inconsistency by setting m_first to null or if it has been | |
| 55 // updated by the writer already then we should just to give up | |
| 56 Interlocked.CompareExchange(ref m_first, null, first); | |
| 57 break; | |
| 58 | |
| 59 } | |
| 60 if (first == Interlocked.CompareExchange(ref m_first, next, first)) | |
| 61 // head succesfully updated | |
| 62 break; | |
| 63 } while (true); | |
| 64 | |
| 65 node = first; | |
| 66 return true; | |
| 67 } | |
| 68 | |
| 69 #region IEnumerable implementation | |
| 70 | |
| 71 class Enumerator : IEnumerator<TNode> { | |
| 72 TNode m_current; | |
| 73 TNode m_first; | |
| 74 | |
| 75 public Enumerator(TNode first) { | |
| 76 m_first = first; | |
| 77 } | |
| 78 | |
| 79 #region IEnumerator implementation | |
| 80 | |
| 81 public bool MoveNext() { | |
| 82 m_current = m_current == null ? m_first : m_current.next; | |
| 83 return m_current != null; | |
| 84 } | |
| 85 | |
| 86 public void Reset() { | |
| 87 m_current = null; | |
| 88 } | |
| 89 | |
| 90 object IEnumerator.Current { | |
| 91 get { | |
| 92 if (m_current == null) | |
| 93 throw new InvalidOperationException(); | |
| 94 return m_current; | |
| 95 } | |
| 96 } | |
| 97 | |
| 98 #endregion | |
| 99 | |
| 100 #region IDisposable implementation | |
| 101 | |
| 102 public void Dispose() { | |
| 103 } | |
| 104 | |
| 105 #endregion | |
| 106 | |
| 107 #region IEnumerator implementation | |
| 108 | |
| 109 public TNode Current { | |
| 110 get { | |
| 111 if (m_current == null) | |
| 112 throw new InvalidOperationException(); | |
| 113 return m_current; | |
| 114 } | |
| 115 } | |
| 116 | |
| 117 #endregion | |
| 118 } | |
| 119 | |
| 120 public IEnumerator<TNode> GetEnumerator() { | |
| 121 return new Enumerator(m_first); | |
| 122 } | |
| 123 | |
| 124 #endregion | |
| 125 | |
| 126 #region IEnumerable implementation | |
| 127 | |
| 128 IEnumerator IEnumerable.GetEnumerator() { | |
| 129 return GetEnumerator(); | |
| 130 } | |
| 131 | |
| 132 #endregion | |
| 133 } | |
| 134 } | |
| 135 |
