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 |