diff Implab/Parallels/SimpleAsyncQueue.cs @ 242:cbe10ac0731e v3

Working on promises
author cin
date Wed, 24 Jan 2018 03:03:21 +0300
parents d6fe09f5592c
children
line wrap: on
line diff
--- a/Implab/Parallels/SimpleAsyncQueue.cs	Tue Jan 23 19:39:21 2018 +0300
+++ b/Implab/Parallels/SimpleAsyncQueue.cs	Wed Jan 24 03:03:21 2018 +0300
@@ -15,12 +15,12 @@
 
         // the reader and the writer are mainteined completely independent,
         // the reader can read next item when m_first.next is not null
-        // the writer creates the a new node, moves m_last to this node and
+        // the writer creates a new node, moves m_last to this node and
         // only after that restores the reference from the previous node
-        // making available the reader to read the new node.
+        // making the reader be able to read the new node.
 
-        Node m_first; // position on the node which is already read
-        Node m_last; // position on the node which is already written
+        volatile Node m_first; // position on the node which is already read
+        volatile Node m_last; // position on the node which is already written
 
         public SimpleAsyncQueue() {
             m_first = m_last = new Node(default(T));
@@ -35,29 +35,38 @@
 
             // release-fence
             last.next = next;
-            
+
         }
 
         public bool TryDequeue(out T value) {
-            Node first;
-            Node next;
+            Node first = m_first; ;
+            Node next = first.next; ;
+
+            if (next == null) {
+                value = default(T);
+                return false;
+            }
+
+            var first2 = Interlocked.CompareExchange(ref m_first, next, first);
+
+            if (first != first2) {
+                // head is updated by someone else
 
-            Thread.MemoryBarrier(); // ensure m_first is fresh
-            SpinWait spin = new SpinWait();
-            do {
-                first = m_first;
-                // aquire-fence
-                next = first.next;
-                if (next == null) {
-                    value = default(T);
-                    return false;
-                }
-                
-                if (first == Interlocked.CompareExchange(ref m_first, next, first))
-                    // head succesfully updated
-                    break;
-                spin.SpinOnce();
-            } while (true);
+                SpinWait spin = new SpinWait();
+                do {
+                    first = first2;
+                    next = first.next;
+                    if (next == null) {
+                        value = default(T);
+                        return false;
+                    }
+
+                    first2 = Interlocked.CompareExchange(ref m_first, next, first);
+                    if (first == first2)
+                        break;
+                    spin.SpinOnce();
+                } while (true);
+            }
 
             value = next.value;
             return true;