Mercurial > pub > ImplabNet
annotate Implab/Parallels/MTQueue.cs @ 93:dc4942d09e74 v2
improved tracing
added the application components container MTComponentContainer.AppContainer
| author | cin |
|---|---|
| date | Thu, 23 Oct 2014 01:13:57 +0400 |
| parents | 4f20870d0816 |
| children | b11c7e9d93bc |
| rev | line source |
|---|---|
| 93 | 1 using System.Threading; |
| 14 | 2 |
| 3 namespace Implab.Parallels { | |
| 4 public class MTQueue<T> { | |
| 5 class Node { | |
| 6 public Node(T value) { | |
| 7 this.value = value; | |
| 8 } | |
| 9 public readonly T value; | |
| 10 public Node next; | |
| 11 } | |
| 12 | |
| 13 Node m_first; | |
| 14 Node m_last; | |
| 15 | |
| 16 public void Enqueue(T value) { | |
| 80 | 17 Thread.MemoryBarrier(); |
| 18 | |
| 14 | 19 var last = m_last; |
| 20 var next = new Node(value); | |
| 21 | |
| 22 while (last != Interlocked.CompareExchange(ref m_last, next, last)) | |
| 23 last = m_last; | |
| 24 | |
| 25 if (last != null) | |
| 26 last.next = next; | |
| 27 else | |
| 28 m_first = next; | |
| 29 } | |
| 30 | |
| 31 public bool TryDequeue(out T value) { | |
| 32 Node first; | |
| 93 | 33 Node next; |
| 14 | 34 value = default(T); |
| 35 | |
| 80 | 36 Thread.MemoryBarrier(); |
| 14 | 37 do { |
| 38 first = m_first; | |
| 39 if (first == null) | |
| 40 return false; | |
| 41 next = first.next; | |
| 42 if (next == null) { | |
| 43 // this is the last element, | |
|
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
14
diff
changeset
|
44 // then try to update the tail |
| 14 | 45 if (first != Interlocked.CompareExchange(ref m_last, null, first)) { |
| 71 | 46 // this is the race condition |
| 14 | 47 if (m_last == null) |
|
19
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
cin
parents:
14
diff
changeset
|
48 // the queue is empty |
| 14 | 49 return false; |
| 71 | 50 // tail has been changed, we need to restart |
| 14 | 51 continue; |
| 52 } | |
| 53 | |
| 54 // tail succesfully updated and first.next will never be changed | |
| 71 | 55 // other readers will fail due to inconsistency m_last != m_fist && m_first.next == null |
| 56 // however the parallel writer may update the m_first since the m_last is null | |
| 14 | 57 |
| 71 | 58 // so we need to fix inconsistency by setting m_first to null or if it has been |
| 59 // updated by the writer already then we should just to give up | |
| 14 | 60 Interlocked.CompareExchange(ref m_first, null, first); |
| 61 break; | |
| 62 | |
| 63 } | |
| 93 | 64 if (first == Interlocked.CompareExchange(ref m_first, next, first)) |
| 65 // head succesfully updated | |
| 66 break; | |
| 14 | 67 } while (true); |
| 68 | |
| 69 value = first.value; | |
| 70 return true; | |
| 71 } | |
| 72 } | |
| 73 } |
