Mirror of Svelto.ECS because we're a fan of it
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

142 lines
3.9KB

  1. using System.Collections.Generic;
  2. using System.Threading;
  3. //from unify wiki
  4. namespace Svelto.DataStructures
  5. {
  6. public class SingleLinkNode<T>
  7. {
  8. // Note; the Next member cannot be a property since
  9. // it participates in many CAS operations
  10. public SingleLinkNode<T> Next;
  11. public T Item;
  12. }
  13. public static class SyncMethods
  14. {
  15. public static bool CAS<T>(ref T location, T comparand, T newValue) where T : class
  16. {
  17. return
  18. (object)comparand ==
  19. (object)Interlocked.CompareExchange<T>(ref location, newValue, comparand);
  20. }
  21. }
  22. public class LockFreeLinkPool<T>
  23. {
  24. private SingleLinkNode<T> head;
  25. public LockFreeLinkPool()
  26. {
  27. head = new SingleLinkNode<T>();
  28. }
  29. public void Push(SingleLinkNode<T> newNode)
  30. {
  31. newNode.Item = default(T);
  32. do
  33. {
  34. newNode.Next = head.Next;
  35. } while (!SyncMethods.CAS<SingleLinkNode<T>>(ref head.Next, newNode.Next, newNode));
  36. return;
  37. }
  38. public bool Pop(out SingleLinkNode<T> node)
  39. {
  40. do
  41. {
  42. node = head.Next;
  43. if (node == null)
  44. {
  45. return false;
  46. }
  47. } while (!SyncMethods.CAS<SingleLinkNode<T>>(ref head.Next, node, node.Next));
  48. return true;
  49. }
  50. }
  51. public class LockFreeQueue<T>
  52. {
  53. SingleLinkNode<T> head;
  54. SingleLinkNode<T> tail;
  55. LockFreeLinkPool<T> trash;
  56. public LockFreeQueue()
  57. {
  58. head = new SingleLinkNode<T>();
  59. tail = head;
  60. trash = new LockFreeLinkPool<T>();
  61. }
  62. public void Enqueue(T item)
  63. {
  64. SingleLinkNode<T> oldTail = null;
  65. SingleLinkNode<T> oldTailNext;
  66. SingleLinkNode<T> newNode;
  67. if (!trash.Pop(out newNode))
  68. {
  69. newNode = new SingleLinkNode<T>();
  70. }
  71. else
  72. {
  73. newNode.Next = null;
  74. }
  75. newNode.Item = item;
  76. bool newNodeWasAdded = false;
  77. while (!newNodeWasAdded)
  78. {
  79. oldTail = tail;
  80. oldTailNext = oldTail.Next;
  81. if (tail == oldTail)
  82. {
  83. if (oldTailNext == null)
  84. newNodeWasAdded = SyncMethods.CAS<SingleLinkNode<T>>(ref tail.Next, null, newNode);
  85. else
  86. SyncMethods.CAS<SingleLinkNode<T>>(ref tail, oldTail, oldTailNext);
  87. }
  88. }
  89. SyncMethods.CAS<SingleLinkNode<T>>(ref tail, oldTail, newNode);
  90. }
  91. public bool Dequeue(out T item)
  92. {
  93. item = default(T);
  94. SingleLinkNode<T> oldHead = null;
  95. bool haveAdvancedHead = false;
  96. while (!haveAdvancedHead)
  97. {
  98. oldHead = head;
  99. SingleLinkNode<T> oldTail = tail;
  100. SingleLinkNode<T> oldHeadNext = oldHead.Next;
  101. if (oldHead == head)
  102. {
  103. if (oldHead == oldTail)
  104. {
  105. if (oldHeadNext == null)
  106. {
  107. return false;
  108. }
  109. SyncMethods.CAS<SingleLinkNode<T>>(ref tail, oldTail, oldHeadNext);
  110. }
  111. else
  112. {
  113. item = oldHeadNext.Item;
  114. haveAdvancedHead = SyncMethods.CAS<SingleLinkNode<T>>(ref head, oldHead, oldHeadNext);
  115. if (haveAdvancedHead)
  116. {
  117. trash.Push(oldHead);
  118. }
  119. }
  120. }
  121. }
  122. return true;
  123. }
  124. }
  125. }