Snzi.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. #if NET_4_0
  2. //
  3. // Snzi.cs
  4. //
  5. // Author:
  6. // Jérémie "Garuma" Laval <[email protected]>
  7. //
  8. // Copyright (c) 2009 Jérémie "Garuma" Laval
  9. //
  10. // Permission is hereby granted, free of charge, to any person obtaining a copy
  11. // of this software and associated documentation files (the "Software"), to deal
  12. // in the Software without restriction, including without limitation the rights
  13. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  14. // copies of the Software, and to permit persons to whom the Software is
  15. // furnished to do so, subject to the following conditions:
  16. //
  17. // The above copyright notice and this permission notice shall be included in
  18. // all copies or substantial portions of the Software.
  19. //
  20. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  21. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  22. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  23. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  24. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  25. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  26. // THE SOFTWARE.
  27. using System;
  28. using System.IO;
  29. namespace System.Threading
  30. {
  31. internal interface ISnziNode
  32. {
  33. bool Query { get; }
  34. void Arrive ();
  35. void Depart ();
  36. bool Reset ();
  37. }
  38. internal class Snzi
  39. {
  40. readonly ISnziNode root;
  41. readonly ISnziNode[] nodes;
  42. readonly int count = Environment.ProcessorCount;
  43. public Snzi ()
  44. {
  45. nodes = new ISnziNode[count];
  46. root = new RootNode ();
  47. for (int i = 0; i < count; i++)
  48. nodes[i] = new LeafNode (root);
  49. }
  50. public void Increment ()
  51. {
  52. ISnziNode node = nodes[GetRandomIndex ()];
  53. node.Arrive ();
  54. }
  55. public void Decrement ()
  56. {
  57. ISnziNode node = nodes[GetRandomIndex ()];
  58. node.Depart ();
  59. }
  60. public void Reset ()
  61. {
  62. ISnziNode node = nodes[GetRandomIndex ()];
  63. node.Reset ();
  64. }
  65. public bool IsSet {
  66. get {
  67. return !root.Query;
  68. }
  69. }
  70. int GetRandomIndex ()
  71. {
  72. return (Thread.CurrentThread.ManagedThreadId) % count;
  73. }
  74. class UnsafeLeafNode : ISnziNode
  75. {
  76. ISnziNode parent;
  77. int var;
  78. public UnsafeLeafNode (ISnziNode parent)
  79. {
  80. this.parent = parent;
  81. }
  82. #region ISnziNode implementation
  83. public void Arrive ()
  84. {
  85. int c = var++;
  86. if (c == 0)
  87. parent.Arrive ();
  88. }
  89. public void Depart ()
  90. {
  91. int c = var--;
  92. if (c == 1)
  93. parent.Depart ();
  94. }
  95. public bool Reset ()
  96. {
  97. throw new System.NotImplementedException();
  98. }
  99. public bool Query {
  100. get {
  101. return parent.Query;
  102. }
  103. }
  104. #endregion
  105. }
  106. class LeafNode : ISnziNode
  107. {
  108. ISnziNode parent;
  109. int var;
  110. public LeafNode (ISnziNode parent)
  111. {
  112. this.parent = parent;
  113. this.var = 0;
  114. }
  115. #region ISnziNode implementation
  116. public void Arrive ()
  117. {
  118. bool succ = false;
  119. int undoArr = 0;
  120. while (!succ) {
  121. int x = var;
  122. short c, v;
  123. Decode (x, out c, out v);
  124. if (c >= 1)
  125. if (Interlocked.CompareExchange (ref var, Encode ((short)(c + 1), v), x) == x)
  126. break;
  127. if (c == 0) {
  128. int temp = Encode (-1, (short)(v + 1));
  129. if (Interlocked.CompareExchange (ref var, temp, x) == x) {
  130. succ = true;
  131. c = -1;
  132. v += 1;
  133. x = temp;
  134. }
  135. }
  136. if (c == - 1) {
  137. parent.Arrive ();
  138. if (Interlocked.CompareExchange (ref var, Encode (1, v), x) != x)
  139. undoArr += 1;
  140. }
  141. }
  142. for (int i = 0; i < undoArr; i++)
  143. parent.Depart ();
  144. }
  145. public void Depart ()
  146. {
  147. while (true) {
  148. int x = var;
  149. short c, v;
  150. Decode (x, out c, out v);
  151. if (Interlocked.CompareExchange (ref var, Encode ((short)(c - 1), v), x) == x) {
  152. if (c == 1)
  153. parent.Depart ();
  154. return;
  155. }
  156. }
  157. }
  158. public bool Reset ()
  159. {
  160. throw new System.NotImplementedException();
  161. }
  162. public bool Query {
  163. get {
  164. return parent.Query;
  165. }
  166. }
  167. #endregion
  168. int Encode (short c, short v)
  169. {
  170. uint temp = 0;
  171. temp |= (uint)c;
  172. temp |= ((uint)v) << 16;
  173. return (int)temp;
  174. }
  175. void Decode (int value, out short c, out short v)
  176. {
  177. uint temp = (uint)value;
  178. c = (short)(temp & 0xFFFF);
  179. v = (short)(temp >> 16);
  180. }
  181. }
  182. class RootNode : ISnziNode
  183. {
  184. int var = 0;
  185. int state = 0;
  186. #region ISnziNode implementation
  187. public void Arrive ()
  188. {
  189. int temp, x = 0;
  190. short c, v;
  191. bool a;
  192. do {
  193. x = var;
  194. Decode (x, out c, out a, out v);
  195. if (c == 0)
  196. temp = Encode (1, true, (short)(v + 1));
  197. else
  198. temp = Encode ((short)(c + 1), a, v);
  199. } while (Interlocked.CompareExchange (ref var, temp, x) != x);
  200. Decode (temp, out c, out a, out v);
  201. if (a) {
  202. while (true) {
  203. int i = state;
  204. int newI = (i & 0x7FFFFFFF) + 1;
  205. newI = (int)(((uint)newI) | 0x80000000);
  206. if (Interlocked.CompareExchange (ref state, newI, i) == i) {
  207. break;
  208. }
  209. }
  210. Interlocked.CompareExchange (ref var, Encode (c, false, v), temp);
  211. }
  212. }
  213. public void Depart ()
  214. {
  215. while (true) {
  216. int x = var;
  217. short c, v;
  218. bool a;
  219. Decode (x, out c, out a, out v);
  220. if (Interlocked.CompareExchange (ref var, Encode ((short)(c - 1), false, v), x) == x) {
  221. if (c >= 2)
  222. return;
  223. while (true) {
  224. int i = state;
  225. if (((short)(var >> 16)) != v)
  226. return;
  227. int newI = (i & 0x7FFFFFFF) + 1;
  228. if (Interlocked.CompareExchange (ref state, newI, i) == i) {
  229. return;
  230. }
  231. }
  232. }
  233. }
  234. }
  235. public bool Reset ()
  236. {
  237. throw new System.NotImplementedException();
  238. }
  239. public bool Query {
  240. get {
  241. return (state & 0x80000000) > 0;
  242. }
  243. }
  244. #endregion
  245. int Encode (short c, bool a, short v)
  246. {
  247. uint temp = 0;
  248. temp |= (uint)c;
  249. temp |= (uint)(a ? 0x8000 : 0);
  250. temp |= ((uint)v) << 16;
  251. return (int)temp;
  252. }
  253. void Decode (int value, out short c, out bool a, out short v)
  254. {
  255. uint temp = (uint)value;
  256. c = (short)(temp & 0x7FFF);
  257. a = (temp & 0x8000) > 0;
  258. v = (short)(temp >> 16);
  259. }
  260. }
  261. }
  262. }
  263. #endif