diff --git a/Implab/Implab.csproj b/Implab/Implab.csproj
--- a/Implab/Implab.csproj
+++ b/Implab/Implab.csproj
@@ -150,6 +150,8 @@
+
+
diff --git a/Implab/Parallels/MTLinkedList.cs b/Implab/Parallels/MTLinkedList.cs
new file mode 100644
--- /dev/null
+++ b/Implab/Parallels/MTLinkedList.cs
@@ -0,0 +1,140 @@
+using System;
+using System.Threading;
+
+namespace Implab.Parallels {
+ public class MTLinkedList where TNode : MTLinkedListNode {
+ 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 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 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;
+ }
+ }
+
+ }
+}
+
diff --git a/Implab/Parallels/MTLinkedListNode.cs b/Implab/Parallels/MTLinkedListNode.cs
new file mode 100644
--- /dev/null
+++ b/Implab/Parallels/MTLinkedListNode.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Implab.Parallels {
+ public class MTLinkedListNode where T : MTLinkedListNode {
+ public MTLinkedList parentList;
+ public TNode next;
+ public TNode prev;
+ }
+}
+