2 // This file is part of the LWES .NET Binding (LWES.net)
4 // Code in this file is based on code by Idaho Edokpayi found at
5 // http://www.codeproject.com/KB/cpp/lockfreeq.aspx?fid=996469&df=90&mpp=25&noise=3&sort=Position&view=Quick
6 // Idaho Edokpayi's code is covered by the Code Project Open License (CPOL)
7 // found at http://www.codeproject.com/info/cpol10.aspx
9 // I have modified the code to use C# idioms that I am fond of; previously
10 // it resembled a port of C++ code and carried over those idioms.
12 // COPYRIGHT (C) 2009, Phillip Clark (cerebralkungfu[at*g mail[dot*com)
13 // original .NET implementation
15 // LWES.net is free software: you can redistribute it and/or modify
16 // it under the terms of the Lesser GNU General Public License as published by
17 // the Free Software Foundation, either version 3 of the License, or
18 // (at your option) any later version.
20 // LWES.net is distributed in the hope that it will be useful,
21 // but WITHOUT ANY WARRANTY; without even the implied warranty of
22 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 // GNU General Public License for more details.
25 // You should have received a copy of the Lesser GNU General Public License
26 // along with LWES.net. If not, see <http://www.gnu.org/licenses/>.
31 using System
.Threading
;
34 /// Simple implementation of a lock-free queue.
36 /// <typeparam name="T">queued item type T</typeparam>
37 public class SimpleLockFreeQueue
<T
>
41 private NodeRec _head
;
42 private NodeRec _tail
;
49 /// Creates a new instance.
51 public SimpleLockFreeQueue()
53 Node node
= new Node();
54 _head
.Node
= _tail
.Node
= node
;
57 #endregion Constructors
62 /// Determines if the queue is empty. Because of the non-blocking nature of the queue there is no guarantee
63 /// made about the availablility of items in the queue after this call. At best it can serve as an indicator.
71 NodeRec next
= head
.Node
.Next
;
73 // Are head, tail, and next consistent?
74 if (head
.Count
== _head
.Count
75 && head
.Node
== _head
.Node
76 && head
.Node
== tail
.Node
91 /// Dequeues an item if it is available in the queue.
93 /// <param name="item">the next available item in the queue, otherwise default(T).</param>
94 /// <returns><em>true</em> if an queued item was retreived by the call, otherwise <em>false</em></returns>
95 public bool Dequeue(out T item
)
99 // Keep trying until we get an item or the queue is empty
106 NodeRec tail
= _tail
;
109 NodeRec next
= head
.Node
.Next
;
111 // Are head, tail, and next consistent?
112 if (head
.Count
== _head
.Count
&& head
.Node
== _head
.Node
)
114 // is tail falling behind
115 if (head
.Node
== tail
.Node
)
117 if (null == next
.Node
)
119 // queue is empty, we're done.
123 // Tail is falling behind. try to advance it
124 CAS(ref _tail
, tail
, new NodeRec(next
.Node
, tail
.Count
+ 1));
128 // No need to deal with tail,
129 // read value before CAS otherwise concurrent op might try to free the next node
130 item
= next
.Node
.Value
;
132 // try to swing the head to the next node
133 if (CAS(ref _head
, head
, new NodeRec(next
.Node
, head
.Count
+ 1)))
146 /// Enqueues an item.
148 /// <param name="item">The item to place in the queue</param>
149 public void Enqueue(T item
)
151 Node node
= new Node();
156 NodeRec tail
= _tail
;
157 NodeRec next
= tail
.Node
.Next
;
159 if (tail
.Count
== _tail
.Count
&& tail
.Node
== _tail
.Node
)
161 if (null == next
.Node
)
163 // Tail was pointing at the last node
164 if (CAS(ref tail
.Node
.Next
, next
, new NodeRec(node
, next
.Count
+ 1)))
171 // tail was not pointing at the last node,
172 // try to swing Tail to the next node
173 CAS(ref _tail
, tail
, new NodeRec(next
.Node
, tail
.Count
+ 1));
179 private bool CAS(ref NodeRec destination
, NodeRec compared
, NodeRec exchange
)
181 if (compared
.Node
== Interlocked
.CompareExchange(ref destination
.Node
, exchange
.Node
, compared
.Node
))
183 Interlocked
.Exchange(ref destination
.Count
, exchange
.Count
);
205 public NodeRec(Node node
, long c
)
211 #endregion Constructors
215 public override string ToString()
217 return String
.Concat("NodeRec { Count = ", Count.ToString(), ", Node = ", Node.ToString(), "}");
234 // Helpful in the debugger when inspecting the node list
235 public override string ToString()
237 return String
.Concat("Node { Next = ", Next
.Count
.ToString(), ", Value = ",
238 (Value
!= null) ? Value
.ToString() : "null", "}");
244 #endregion Nested Types