Mercurial > pub > ImplabNet
diff Implab/Parallels/MTCustomQueue.cs @ 106:d4e38929ce36 v2
promises refactoring
author | cin |
---|---|
date | Mon, 10 Nov 2014 18:00:28 +0300 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Implab/Parallels/MTCustomQueue.cs Mon Nov 10 18:00:28 2014 +0300 @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Collections; + +namespace Implab.Parallels { + public class MTCustomQueue<TNode> : IEnumerable<TNode> where TNode : MTCustomQueueNode<TNode> { + TNode m_first; + TNode m_last; + + public void Enqueue(TNode next) { + Thread.MemoryBarrier(); + + var last = m_last; + + // Interlocaked.CompareExchange implies Thread.MemoryBarrier(); + // to ensure that the next node is completely constructed + while (last != Interlocked.CompareExchange(ref m_last, next, last)) + last = m_last; + + if (last != null) + last.next = next; + else + m_first = next; + } + + public bool TryDequeue(out TNode node) { + TNode first; + TNode next; + node = null; + + Thread.MemoryBarrier(); + do { + first = m_first; + if (first == null) + return false; + next = first.next; + if (next == null) { + // this is the last element, + // then try to update the tail + if (first != Interlocked.CompareExchange(ref m_last, null, first)) { + // this is the race condition + if (m_last == null) + // the queue is empty + return false; + // tail has been changed, we need to restart + continue; + } + + // tail succesfully updated and first.next will never be changed + // other readers will fail due to inconsistency m_last != m_fist && m_first.next == null + // however the parallel writer may update the m_first since the m_last is null + + // so we need to fix inconsistency by setting m_first to null or if it has been + // updated by the writer already then we should just to give up + Interlocked.CompareExchange(ref m_first, null, first); + break; + + } + if (first == Interlocked.CompareExchange(ref m_first, next, first)) + // head succesfully updated + break; + } while (true); + + node = first; + return true; + } + + #region IEnumerable implementation + + class Enumerator : IEnumerator<TNode> { + TNode m_current; + TNode m_first; + + public Enumerator(TNode first) { + m_first = first; + } + + #region IEnumerator implementation + + public bool MoveNext() { + m_current = m_current == null ? m_first : m_current.next; + return m_current != null; + } + + public void Reset() { + m_current = null; + } + + object IEnumerator.Current { + get { + if (m_current == null) + throw new InvalidOperationException(); + return m_current; + } + } + + #endregion + + #region IDisposable implementation + + public void Dispose() { + } + + #endregion + + #region IEnumerator implementation + + public TNode Current { + get { + if (m_current == null) + throw new InvalidOperationException(); + return m_current; + } + } + + #endregion + } + + public IEnumerator<TNode> GetEnumerator() { + return new Enumerator(m_first); + } + + #endregion + + #region IEnumerable implementation + + IEnumerator IEnumerable.GetEnumerator() { + return GetEnumerator(); + } + + #endregion + } +} +