Mercurial > pub > ImplabNet
comparison Implab/Parallels/SimpleAsyncQueue.cs @ 242:cbe10ac0731e v3
Working on promises
| author | cin |
|---|---|
| date | Wed, 24 Jan 2018 03:03:21 +0300 |
| parents | d6fe09f5592c |
| children |
comparison
equal
deleted
inserted
replaced
| 240:fa6cbf4d8841 | 242:cbe10ac0731e |
|---|---|
| 13 public volatile Node next; | 13 public volatile Node next; |
| 14 } | 14 } |
| 15 | 15 |
| 16 // the reader and the writer are mainteined completely independent, | 16 // the reader and the writer are mainteined completely independent, |
| 17 // the reader can read next item when m_first.next is not null | 17 // the reader can read next item when m_first.next is not null |
| 18 // the writer creates the a new node, moves m_last to this node and | 18 // the writer creates a new node, moves m_last to this node and |
| 19 // only after that restores the reference from the previous node | 19 // only after that restores the reference from the previous node |
| 20 // making available the reader to read the new node. | 20 // making the reader be able to read the new node. |
| 21 | 21 |
| 22 Node m_first; // position on the node which is already read | 22 volatile Node m_first; // position on the node which is already read |
| 23 Node m_last; // position on the node which is already written | 23 volatile Node m_last; // position on the node which is already written |
| 24 | 24 |
| 25 public SimpleAsyncQueue() { | 25 public SimpleAsyncQueue() { |
| 26 m_first = m_last = new Node(default(T)); | 26 m_first = m_last = new Node(default(T)); |
| 27 } | 27 } |
| 28 | 28 |
| 33 // to ensure that the next node is completely constructed | 33 // to ensure that the next node is completely constructed |
| 34 var last = Interlocked.Exchange(ref m_last, next); | 34 var last = Interlocked.Exchange(ref m_last, next); |
| 35 | 35 |
| 36 // release-fence | 36 // release-fence |
| 37 last.next = next; | 37 last.next = next; |
| 38 | 38 |
| 39 } | 39 } |
| 40 | 40 |
| 41 public bool TryDequeue(out T value) { | 41 public bool TryDequeue(out T value) { |
| 42 Node first; | 42 Node first = m_first; ; |
| 43 Node next; | 43 Node next = first.next; ; |
| 44 | 44 |
| 45 Thread.MemoryBarrier(); // ensure m_first is fresh | 45 if (next == null) { |
| 46 SpinWait spin = new SpinWait(); | 46 value = default(T); |
| 47 do { | 47 return false; |
| 48 first = m_first; | 48 } |
| 49 // aquire-fence | 49 |
| 50 next = first.next; | 50 var first2 = Interlocked.CompareExchange(ref m_first, next, first); |
| 51 if (next == null) { | 51 |
| 52 value = default(T); | 52 if (first != first2) { |
| 53 return false; | 53 // head is updated by someone else |
| 54 } | 54 |
| 55 | 55 SpinWait spin = new SpinWait(); |
| 56 if (first == Interlocked.CompareExchange(ref m_first, next, first)) | 56 do { |
| 57 // head succesfully updated | 57 first = first2; |
| 58 break; | 58 next = first.next; |
| 59 spin.SpinOnce(); | 59 if (next == null) { |
| 60 } while (true); | 60 value = default(T); |
| 61 return false; | |
| 62 } | |
| 63 | |
| 64 first2 = Interlocked.CompareExchange(ref m_first, next, first); | |
| 65 if (first == first2) | |
| 66 break; | |
| 67 spin.SpinOnce(); | |
| 68 } while (true); | |
| 69 } | |
| 61 | 70 |
| 62 value = next.value; | 71 value = next.value; |
| 63 return true; | 72 return true; |
| 64 } | 73 } |
| 65 | 74 |
