Mercurial > pub > ImplabNet
diff Implab/Parallels/MTLinkedList.cs @ 113:468d156e434e v2-1
working on linked list
author | cin |
---|---|
date | Wed, 10 Dec 2014 01:29:53 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Implab/Parallels/MTLinkedList.cs Wed Dec 10 01:29:53 2014 +0100 @@ -0,0 +1,140 @@ +using System; +using System.Threading; + +namespace Implab.Parallels { + public class MTLinkedList<TNode> where TNode : MTLinkedListNode<TNode> { + TNode m_first; + TNode m_last; + + public void InsertAfter( TNode pos, TNode node) { + Safe.ArgumentNotNull(node, "node"); + if (!Attach(node)) + throw new InvalidOperationException("The specified node already attached to a list"); + + TNode next; + + while (true) { + // insert first if pos == null + next = pos == null ? m_first : pos.next; + node.prev = pos; + node.next = next; + if (next == m_first) { + if (next != Interlocked.CompareExchange(ref m_first, node, next)) + continue; + // race + } else { + if (next != Interlocked.CompareExchange(ref pos.next, node, next)) + continue; + // race + } + break; + } + + while (true) { + if (next == null) { + if (pos != Interlocked.CompareExchange(ref m_last, node, pos)) + continue; + } else { + if (pos != Interlocked.CompareExchange(ref next.prev, node, pos)) + continue; + } + break; + } + } + + public void InsertBefore( TNode pos, TNode node) { + Safe.ArgumentNotNull(node, "node"); + + if (!Attach(node)) + return; + + TNode prev; + + while (true) { + // insert first if pos == null + prev = pos == null ? m_last : pos.prev; + node.next = pos; + node.prev = prev; + if (prev == m_last) { + if (prev != Interlocked.CompareExchange(ref m_last, node, prev)) + continue; + // race + } else { + if (prev != Interlocked.CompareExchange(ref pos.prev, node, prev)) + continue; + // race + } + break; + } + + while (true) { + if (prev == null) { + if (pos != Interlocked.CompareExchange(ref m_first, node, pos)) + continue; + } else { + if (pos != Interlocked.CompareExchange(ref prev.next, node, pos)) + continue; + } + break; + } + } + + bool Detach(TNode node) { + MTLinkedList<TNode> parent; + + do { + parent = node.parentList; + if (parent == null || parent != this) + return false; + } while(parent != Interlocked.CompareExchange(ref node.parentList, null, parent)); + } + + bool Attach(TNode node) { + MTLinkedList<TNode> parent; + + do { + parent = node.parentList; + if (parent != null) + return false; + } while(parent != Interlocked.CompareExchange(ref node.parentList, this, parent)); + } + + public void Remove(TNode node) { + Safe.ArgumentNotNull(node, "node"); + + if (!Detach(node)) + return; + + TNode prev; + TNode next; + + while (true) { + prev = node.prev; + next = node.next; + + if (prev == null) { + if (node != Interlocked.CompareExchange(ref m_first, next, node)) + continue; + } else { + if (node != Interlocked.CompareExchange(ref prev.next, next, node)) + continue; + } + + break; + } + + while (true) { + if (next == null) { + if (node != Interlocked.CompareExchange(ref m_last, prev, node)) + continue; + } else { + if (node != Interlocked.CompareExchange(ref next.prev, prev, node)) + continue; + } + break; + } + } + + } +} +