Guest User

Untitled

a guest
Jan 17th, 2019
101
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.11 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading;
  5.  
  6. namespace ConsoleApplication3
  7. {
  8. internal class State
  9. {
  10. public Object Value;
  11. }
  12.  
  13. internal class Idle : State {}
  14.  
  15. internal class InProgress : State {}
  16.  
  17.  
  18. public class Ref
  19. {
  20. private static long _lastId = 0;
  21. private static long GetId()
  22. {
  23. var id = Interlocked.Increment(ref _lastId);
  24. return id;
  25. }
  26.  
  27. public Ref(object value)
  28. {
  29. this.id = GetId();
  30. this.content = new Idle { Value = value };
  31.  
  32. }
  33.  
  34. public Object Value
  35. {
  36. get
  37. {
  38. return content.Value;
  39. }
  40. }
  41.  
  42. internal long id;
  43. internal State content;
  44. }
  45.  
  46. public class Ref<A> : Ref
  47. {
  48. public Ref(object value) : base(value)
  49. {
  50.  
  51. }
  52. public new A Value
  53. {
  54. get
  55. {
  56. return (A)content.Value;
  57. }
  58. }
  59. }
  60.  
  61. public struct CAS
  62. {
  63. public CAS(Ref refValue, object expect, object update)
  64. {
  65. this.r = refValue;
  66. this.expect = expect;
  67. this.update = update;
  68. }
  69. internal Ref r;
  70. internal object expect;
  71. internal object update;
  72. internal long ID { get { return r.id; } }
  73. }
  74.  
  75.  
  76.  
  77. public static class Atomic
  78. {
  79. /// <summary>
  80. /// Try to acquire a list of CASes and return, in the case of failure, the CASes that must be rolled back
  81. /// </summary>
  82. public static List<CAS> SemiCAS_loop(List<CAS> log, IEnumerable<CAS> l)
  83. {
  84. if (!l.Any())
  85. {
  86. return null;
  87. }
  88.  
  89. var firstCAS = l.First();
  90. var state = firstCAS.r.content;
  91. if (state is Idle)
  92. {
  93. if (state.Value.Equals(firstCAS.expect))
  94. {
  95. // Atomically update state to InProgress
  96. var inProgress = new InProgress { Value = state.Value };
  97. var swap = Interlocked.CompareExchange(ref firstCAS.r.content, inProgress, state);
  98. if (swap.Equals(state))
  99. {
  100. // CAS succeeded, add it to the rollback log and continue
  101. log.Add(firstCAS);
  102. return SemiCAS_loop(log, l.Skip(1));
  103. }
  104. else // CAS failed, return the rollback log.
  105. {
  106. return log;
  107. }
  108. }
  109. else // CAS will fail, ditto.
  110. {
  111. return log;
  112. }
  113. }
  114. else if (firstCAS.r.content is InProgress)
  115. {
  116. // (*This thread lost the race to acquired the CASes. *)
  117. return log;
  118. }
  119. else
  120. {
  121. return log;
  122. }
  123. }
  124.  
  125. public static List<CAS> SemiCAS(IEnumerable<CAS> l)
  126. {
  127. List<CAS> log = new List<CAS>();
  128. return SemiCAS_loop(log, l);
  129. }
  130.  
  131. // Only the thread that performed the semicas should be able to rollbwd/fwd.
  132. // Hence, we don't need to CAS.
  133. public static void Rollbwd(CAS cas)
  134. {
  135. if (cas.r.content is InProgress)
  136. {
  137. cas.r.content = new Idle { Value = cas.r.content.Value };
  138. }
  139. }
  140.  
  141. public static void Rollfwd(CAS cas)
  142. {
  143. if (cas.r.content is Idle)
  144. {
  145. throw new InvalidOperationException("CAS.kCAS: broken invariant");
  146. }
  147. if (cas.r.content is InProgress)
  148. {
  149. // we know we have cas.r.Value == cas.expect
  150. cas.r.content = new Idle { Value = cas.update };
  151. }
  152. }
  153.  
  154. public static bool KCAS(List<CAS> list)
  155. {
  156. // kCAS should sort the list of CAS to do before attempting anything to prevent deadlocks
  157. list.Sort((a, b) => a.ID.CompareTo(b.ID));
  158. var semicas = SemiCAS(list);
  159. if (semicas == null)
  160. {
  161. list.ForEach((cas) => Rollfwd(cas));
  162. return true;
  163. }
  164. else
  165. {
  166. semicas.ForEach((cas) => Rollbwd(cas));
  167. return false;
  168. }
  169. }
  170. public static void Update<A>(List<Ref> list, Func<A, A> func)
  171. {
  172. SpinWait.SpinUntil(() => {
  173. var casList = list.Select((r) => new CAS(r, r.Value, func((A)r.Value))).ToList();
  174. return KCAS(casList);
  175. });
  176. }
  177. }
  178.  
  179. public class Tx
  180. {
  181. Action<Tx> txFunc;
  182. List<CAS> casList;
  183.  
  184. public Tx(Action<Tx> func)
  185. {
  186. txFunc = func;
  187. }
  188.  
  189. public static void Atomically(Action<Tx> func)
  190. {
  191. var tx = new Tx(func);
  192. tx.Commit();
  193. }
  194.  
  195.  
  196. public void Write<A>(Ref<A> refVar, A newValue)
  197. {
  198. var oldValue = refVar.Value;
  199. var cas = new CAS(refVar, oldValue, newValue);
  200. casList.Add(cas);
  201. }
  202.  
  203. public void Update<A>(Ref<A> refVar, Func<A, A> newValueFunc)
  204. {
  205. var oldValue = refVar.Value;
  206. var newValue = newValueFunc((A)oldValue);
  207. var cas = new CAS(refVar, oldValue, newValue);
  208. casList.Add(cas);
  209. }
  210.  
  211. private void Commit()
  212. {
  213. SpinWait.SpinUntil(() => {
  214. casList = new List<CAS>();
  215. txFunc(this);
  216. return Atomic.KCAS(casList);
  217. });
  218. }
  219. }
  220.  
  221. class Program
  222. {
  223. static void Main(string[] args)
  224. {
  225. var a = new Ref<int>(10);
  226. var b = new Ref<int>(20);
  227.  
  228. Tx.Atomically((tx) =>
  229. {
  230. tx.Write(a, a.Value + 1);
  231. tx.Write(b, b.Value + 1);
  232. });
  233.  
  234. Console.WriteLine(a.Value);
  235. Console.WriteLine(b.Value);
  236. int c = Console.Read();
  237. }
  238. }
  239. }
Add Comment
Please, Sign In to add comment