ConcurrentQueue.cs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. // .NET 4.x eq, .NET 4.x => Disable
  2. //PLATFORM_IMPLEMENTS_ATTACH_DIALOG;ENABLE_MONO;NET_4_6;ENABLE_PROFILER;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_WIN;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_BURST_AOT;UNITY_TEAM_LICENSE;ENABLE_VSTU;
  3. //CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER
  4. // .NET 4.x eq, .NET Standard => Disable
  5. // .NET 3.5 eq, .NET 4.x => Enable
  6. //PLATFORM_IMPLEMENTS_ATTACH_DIALOG;ENABLE_MONO;NET_4_6;ENABLE_PROFILER;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_WIN;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_BURST_AOT;UNITY_TEAM_LICENSE;ENABLE_VSTU
  7. // .NET 3.5 eq, .NET 2.0 => Enable
  8. //PLATFORM_IMPLEMENTS_ATTACH_DIALOG;ENABLE_MONO;NET_2_0;NET_LEGACY;ENABLE_PROFILER;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_WIN;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_BURST_AOT;UNITY_TEAM_LICENSE;ENABLE_VSTU
  9. #if !NET_STANDARD_2_0 && !NETFX_CORE && ((NET_4_6 && !CSHARP_7_OR_LATER && UNITY_2018_3_OR_NEWER) || !NET_4_6)
  10. // ConcurrentQueue.cs
  11. //
  12. // Copyright (c) 2008 Jérémie "Garuma" Laval
  13. //
  14. // Permission is hereby granted, free of charge, to any person obtaining a copy
  15. // of this software and associated documentation files (the "Software"), to deal
  16. // in the Software without restriction, including without limitation the rights
  17. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  18. // copies of the Software, and to permit persons to whom the Software is
  19. // furnished to do so, subject to the following conditions:
  20. //
  21. // The above copyright notice and this permission notice shall be included in
  22. // all copies or substantial portions of the Software.
  23. //
  24. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  25. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  26. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  27. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  28. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  29. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  30. // THE SOFTWARE.
  31. //
  32. //
  33. using System.Collections.Generic;
  34. using System.Runtime.Serialization;
  35. using System.Threading;
  36. namespace System.Collections.Concurrent
  37. {
  38. public class ConcurrentQueue<T> : /*IProducerConsumerCollection<T>,*/ IEnumerable<T>, ICollection,
  39. IEnumerable, ISerializable, IDeserializationCallback
  40. {
  41. class Node
  42. {
  43. public T Value;
  44. public Node Next;
  45. }
  46. Node head = new Node();
  47. Node tail;
  48. int count;
  49. public ConcurrentQueue()
  50. {
  51. tail = head;
  52. }
  53. public ConcurrentQueue(IEnumerable<T> enumerable) : this()
  54. {
  55. foreach (T item in enumerable)
  56. {
  57. Enqueue(item);
  58. }
  59. }
  60. protected ConcurrentQueue(SerializationInfo info, StreamingContext context)
  61. {
  62. throw new NotImplementedException();
  63. }
  64. public void Enqueue(T item)
  65. {
  66. Interlocked.Increment(ref count);
  67. Node node = new Node();
  68. node.Value = item;
  69. Node oldTail = null;
  70. Node oldNext = null;
  71. bool update = false;
  72. while (!update)
  73. {
  74. oldTail = tail;
  75. oldNext = oldTail.Next;
  76. // Did tail was already updated ?
  77. if (tail == oldTail)
  78. {
  79. if (oldNext == null)
  80. {
  81. // The place is for us
  82. update = Interlocked.CompareExchange(ref tail.Next, node, null) == null;
  83. }
  84. else
  85. {
  86. // another Thread already used the place so give him a hand by putting tail where it should be
  87. Interlocked.CompareExchange(ref tail, oldNext, oldTail);
  88. }
  89. }
  90. }
  91. // At this point we added correctly our node, now we have to update tail. If it fails then it will be done by another thread
  92. Interlocked.CompareExchange(ref tail, node, oldTail);
  93. }
  94. //bool IProducerConsumerCollection<T>.TryAdd (T item)
  95. //{
  96. // Enqueue (item);
  97. // return true;
  98. //}
  99. /// <summary>
  100. /// </summary>
  101. /// <returns></returns>
  102. public bool TryDequeue(out T value)
  103. {
  104. value = default(T);
  105. bool advanced = false;
  106. while (!advanced)
  107. {
  108. Node oldHead = head;
  109. Node oldTail = tail;
  110. Node oldNext = oldHead.Next;
  111. if (oldHead == head)
  112. {
  113. // Empty case ?
  114. if (oldHead == oldTail)
  115. {
  116. // This should be false then
  117. if (oldNext != null)
  118. {
  119. // If not then the linked list is mal formed, update tail
  120. Interlocked.CompareExchange(ref tail, oldNext, oldTail);
  121. }
  122. value = default(T);
  123. return false;
  124. }
  125. else
  126. {
  127. value = oldNext.Value;
  128. advanced = Interlocked.CompareExchange(ref head, oldNext, oldHead) == oldHead;
  129. }
  130. }
  131. }
  132. Interlocked.Decrement(ref count);
  133. return true;
  134. }
  135. /// <summary>
  136. /// </summary>
  137. /// <returns></returns>
  138. public bool TryPeek(out T value)
  139. {
  140. if (IsEmpty)
  141. {
  142. value = default(T);
  143. return false;
  144. }
  145. Node first = head.Next;
  146. value = first.Value;
  147. return true;
  148. }
  149. internal void Clear()
  150. {
  151. count = 0;
  152. tail = head = new Node();
  153. }
  154. IEnumerator IEnumerable.GetEnumerator()
  155. {
  156. return (IEnumerator)InternalGetEnumerator();
  157. }
  158. IEnumerator<T> IEnumerable<T>.GetEnumerator()
  159. {
  160. return InternalGetEnumerator();
  161. }
  162. public IEnumerator<T> GetEnumerator()
  163. {
  164. return InternalGetEnumerator();
  165. }
  166. IEnumerator<T> InternalGetEnumerator()
  167. {
  168. Node my_head = head;
  169. while ((my_head = my_head.Next) != null)
  170. {
  171. yield return my_head.Value;
  172. }
  173. }
  174. void ICollection.CopyTo(Array array, int index)
  175. {
  176. T[] dest = array as T[];
  177. if (dest == null)
  178. {
  179. return;
  180. }
  181. CopyTo(dest, index);
  182. }
  183. public void CopyTo(T[] dest, int index)
  184. {
  185. IEnumerator<T> e = InternalGetEnumerator();
  186. int i = index;
  187. while (e.MoveNext())
  188. {
  189. dest[i++] = e.Current;
  190. }
  191. }
  192. public T[] ToArray()
  193. {
  194. T[] dest = new T[count];
  195. CopyTo(dest, 0);
  196. return dest;
  197. }
  198. protected virtual void GetObjectData(SerializationInfo info, StreamingContext context)
  199. {
  200. throw new NotImplementedException();
  201. }
  202. void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
  203. {
  204. GetObjectData(info, context);
  205. }
  206. bool ICollection.IsSynchronized
  207. {
  208. get { return true; }
  209. }
  210. protected virtual void OnDeserialization(object sender)
  211. {
  212. throw new NotImplementedException();
  213. }
  214. void IDeserializationCallback.OnDeserialization(object sender)
  215. {
  216. OnDeserialization(sender);
  217. }
  218. //bool IProducerConsumerCollection<T>.TryTake (out T item)
  219. //{
  220. // return TryDequeue (out item);
  221. //}
  222. object syncRoot = new object();
  223. object ICollection.SyncRoot
  224. {
  225. get { return syncRoot; }
  226. }
  227. public int Count
  228. {
  229. get
  230. {
  231. return count;
  232. }
  233. }
  234. public bool IsEmpty
  235. {
  236. get
  237. {
  238. return count == 0;
  239. }
  240. }
  241. }
  242. }
  243. #endif