微软关于CancellationTokenSource的介绍很简单,其实CancellationTokenSource的使用也很简单,但是实现就不是那么简单了,我们首先来看看CancellationTokenSource的实现:

  1. public class CancellationTokenSource : IDisposable
  2. {
  3. private const int CANNOT_BE_CANCELED = ;
  4. private const int NOT_CANCELED = ;
  5. private const int NOTIFYING = ;
  6. private const int NOTIFYINGCOMPLETE = ;
  7.  
  8. private volatile int m_state;
  9. private static readonly Action<object> s_LinkedTokenCancelDelegate = new Action<object>(LinkedTokenCancelDelegate);
  10. private static readonly int s_nLists = (PlatformHelper.ProcessorCount > ) ? : PlatformHelper.ProcessorCount;
  11. private volatile CancellationCallbackInfo m_executingCallback;
  12. private volatile SparselyPopulatedArray<CancellationCallbackInfo>[] m_registeredCallbacksLists;
  13. private static readonly TimerCallback s_timerCallback = new TimerCallback(TimerCallbackLogic);
  14. private volatile Timer m_timer;
  15.  
  16. public CancellationTokenSource()
  17. {
  18. m_state = NOT_CANCELED;
  19. }
  20.  
  21. //Constructs a CancellationTokenSource that will be canceled after a specified time span.
  22. public CancellationTokenSource(Int32 millisecondsDelay)
  23. {
  24. if (millisecondsDelay < -)
  25. {
  26. throw new ArgumentOutOfRangeException("millisecondsDelay");
  27. }
  28.  
  29. InitializeWithTimer(millisecondsDelay);
  30. }
  31.  
  32. private void InitializeWithTimer(Int32 millisecondsDelay)
  33. {
  34. m_state = NOT_CANCELED;
  35. m_timer = new Timer(s_timerCallback, this, millisecondsDelay, -1);
  36. }
  37.  
  38. private static void TimerCallbackLogic(object obj)
  39. {
  40. CancellationTokenSource cts = (CancellationTokenSource)obj;
  41. if (!cts.IsDisposed)
  42. {
  43. try
  44. {
  45. cts.Cancel(); // will take care of disposing of m_timer
  46. }
  47. catch (ObjectDisposedException)
  48. {
  49. if (!cts.IsDisposed) throw;
  50. }
  51. }
  52. }
  53.  
  54. public void Cancel()
  55. {
  56. Cancel(false);
  57. }
  58.  
  59. public void Cancel(bool throwOnFirstException)
  60. {
  61. ThrowIfDisposed();
  62. NotifyCancellation(throwOnFirstException);
  63. }
  64.  
  65. public void CancelAfter(Int32 millisecondsDelay)
  66. {
  67. ThrowIfDisposed();
  68.  
  69. if (millisecondsDelay < -)
  70. {
  71. throw new ArgumentOutOfRangeException("millisecondsDelay");
  72. }
  73.  
  74. if (IsCancellationRequested) return;
  75. if (m_timer == null)
  76. {
  77. Timer newTimer = new Timer(s_timerCallback, this, -1, -1);
  78. if (Interlocked.CompareExchange(ref m_timer, newTimer, null) != null)
  79. {
  80. newTimer.Dispose();
  81. }
  82. }
  83.  
  84. // It is possible that m_timer has already been disposed, so we must do
  85. // the following in a try/catch block.
  86. try
  87. {
  88. m_timer.Change(millisecondsDelay, -1);
  89. }
  90. catch (ObjectDisposedException)
  91. {
  92. }
  93. }
  94.  
  95. private void NotifyCancellation(bool throwOnFirstException)
  96. {
  97. if (IsCancellationRequested)
  98. return;
  99.  
  100. // If we're the first to signal cancellation, do the main extra work.
  101. if (Interlocked.CompareExchange(ref m_state, NOTIFYING, NOT_CANCELED) == NOT_CANCELED)
  102. {
  103. Timer timer = m_timer;
  104. if(timer != null) timer.Dispose();
  105.  
  106. //record the threadID being used for running the callbacks.
  107. ThreadIDExecutingCallbacks = Thread.CurrentThread.ManagedThreadId;
  108.  
  109. //If the kernel event is null at this point, it will be set during lazy construction.
  110. if (m_kernelEvent != null)
  111. m_kernelEvent.Set(); // update the MRE value.
  112.  
  113. ExecuteCallbackHandlers(throwOnFirstException);
  114. Contract.Assert(IsCancellationCompleted, "Expected cancellation to have finished");
  115. }
  116. }
  117.  
  118. /// Invoke the Canceled event. The handlers are invoked synchronously in LIFO order.
  119. private void ExecuteCallbackHandlers(bool throwOnFirstException)
  120. {
  121. Contract.Assert(IsCancellationRequested, "ExecuteCallbackHandlers should only be called after setting IsCancellationRequested->true");
  122. Contract.Assert(ThreadIDExecutingCallbacks != -, "ThreadIDExecutingCallbacks should have been set.");
  123.  
  124. List<Exception> exceptionList = null;
  125. SparselyPopulatedArray<CancellationCallbackInfo>[] callbackLists = m_registeredCallbacksLists;
  126.  
  127. if (callbackLists == null)
  128. {
  129. Interlocked.Exchange(ref m_state, NOTIFYINGCOMPLETE);
  130. return;
  131. }
  132.  
  133. try
  134. {
  135. for (int index = ; index < callbackLists.Length; index++)
  136. {
  137. SparselyPopulatedArray<CancellationCallbackInfo> list = Volatile.Read<SparselyPopulatedArray<CancellationCallbackInfo>>(ref callbackLists[index]);
  138. if (list != null)
  139. {
  140. SparselyPopulatedArrayFragment<CancellationCallbackInfo> currArrayFragment = list.Tail;
  141.  
  142. while (currArrayFragment != null)
  143. {
  144. for (int i = currArrayFragment.Length - ; i >= ; i--)
  145. {
  146. m_executingCallback = currArrayFragment[i];
  147. if (m_executingCallback != null)
  148. {
  149. CancellationCallbackCoreWorkArguments args = new CancellationCallbackCoreWorkArguments(currArrayFragment, i);
  150. try
  151. {
  152. if (m_executingCallback.TargetSyncContext != null)
  153. {
  154. m_executingCallback.TargetSyncContext.Send(CancellationCallbackCoreWork_OnSyncContext, args);
  155. ThreadIDExecutingCallbacks = Thread.CurrentThread.ManagedThreadId;
  156. }
  157. else
  158. {
  159. CancellationCallbackCoreWork(args);
  160. }
  161. }
  162. catch(Exception ex)
  163. {
  164. if (throwOnFirstException)
  165. throw;
  166. if(exceptionList == null)
  167. exceptionList = new List<Exception>();
  168. exceptionList.Add(ex);
  169. }
  170. }
  171. }
  172. currArrayFragment = currArrayFragment.Prev;
  173. }
  174. }
  175. }
  176. }
  177. finally
  178. {
  179. m_state = NOTIFYINGCOMPLETE;
  180. m_executingCallback = null;
  181. Thread.MemoryBarrier(); // for safety, prevent reorderings crossing this point and seeing inconsistent state.
  182. }
  183.  
  184. if (exceptionList != null)
  185. {
  186. Contract.Assert(exceptionList.Count > , "Expected exception count > 0");
  187. throw new AggregateException(exceptionList);
  188. }
  189. }
  190.  
  191. private void CancellationCallbackCoreWork_OnSyncContext(object obj)
  192. {
  193. CancellationCallbackCoreWork((CancellationCallbackCoreWorkArguments)obj);
  194. }
  195.  
  196. private void CancellationCallbackCoreWork(CancellationCallbackCoreWorkArguments args)
  197. {
  198. CancellationCallbackInfo callback = args.m_currArrayFragment.SafeAtomicRemove(args.m_currArrayIndex, m_executingCallback);
  199. if (callback == m_executingCallback)
  200. {
  201. if (callback.TargetExecutionContext != null)
  202. {
  203. callback.CancellationTokenSource.ThreadIDExecutingCallbacks = Thread.CurrentThread.ManagedThreadId;
  204. }
  205. callback.ExecuteCallback();
  206. }
  207. }
  208.  
  209. public static CancellationTokenSource CreateLinkedTokenSource(CancellationToken token1, CancellationToken token2)
  210. {
  211. CancellationTokenSource linkedTokenSource = new CancellationTokenSource();
  212. bool token2CanBeCanceled = token2.CanBeCanceled;
  213.  
  214. if( token1.CanBeCanceled )
  215. {
  216. linkedTokenSource.m_linkingRegistrations = new CancellationTokenRegistration[token2CanBeCanceled ? : ]; // there will be at least 1 and at most 2 linkings
  217. linkedTokenSource.m_linkingRegistrations[] = token1.InternalRegisterWithoutEC(s_LinkedTokenCancelDelegate, linkedTokenSource);
  218. }
  219.  
  220. if( token2CanBeCanceled )
  221. {
  222. int index = ;
  223. if( linkedTokenSource.m_linkingRegistrations == null )
  224. {
  225. linkedTokenSource.m_linkingRegistrations = new CancellationTokenRegistration[]; // this will be the only linking
  226. index = ;
  227. }
  228. linkedTokenSource.m_linkingRegistrations[index] = token2.InternalRegisterWithoutEC(s_LinkedTokenCancelDelegate, linkedTokenSource);
  229. }
  230. return linkedTokenSource;
  231. }
  232.  
  233. public static CancellationTokenSource CreateLinkedTokenSource(params CancellationToken[] tokens)
  234. {
  235. if (tokens == null)
  236. throw new ArgumentNullException("tokens");
  237.  
  238. if (tokens.Length == )
  239. throw new ArgumentException(Environment.GetResourceString("CancellationToken_CreateLinkedToken_TokensIsEmpty"));
  240.  
  241. Contract.EndContractBlock();
  242.  
  243. CancellationTokenSource linkedTokenSource = new CancellationTokenSource();
  244. linkedTokenSource.m_linkingRegistrations = new CancellationTokenRegistration[tokens.Length];
  245.  
  246. for (int i = ; i < tokens.Length; i++)
  247. {
  248. if (tokens[i].CanBeCanceled)
  249. {
  250. linkedTokenSource.m_linkingRegistrations[i] = tokens[i].InternalRegisterWithoutEC(s_LinkedTokenCancelDelegate, linkedTokenSource);
  251. }
  252. }
  253. return linkedTokenSource;
  254. }
  255.  
  256. internal CancellationTokenRegistration InternalRegister(Action<object> callback, object stateForCallback, SynchronizationContext targetSyncContext, ExecutionContext executionContext)
  257. {
  258. if (AppContextSwitches.ThrowExceptionIfDisposedCancellationTokenSource)
  259. {
  260. ThrowIfDisposed();
  261. }
  262. Contract.Assert(CanBeCanceled, "Cannot register for uncancelable token src");
  263. if (!IsCancellationRequested)
  264. {
  265. if (m_disposed && !AppContextSwitches.ThrowExceptionIfDisposedCancellationTokenSource)
  266. return new CancellationTokenRegistration();
  267.  
  268. int myIndex = Thread.CurrentThread.ManagedThreadId % s_nLists;
  269.  
  270. CancellationCallbackInfo callbackInfo = new CancellationCallbackInfo(callback, stateForCallback, targetSyncContext, executionContext, this);
  271.  
  272. //allocate the callback list array
  273. var registeredCallbacksLists = m_registeredCallbacksLists;
  274. if (registeredCallbacksLists == null)
  275. {
  276. SparselyPopulatedArray<CancellationCallbackInfo>[] list = new SparselyPopulatedArray<CancellationCallbackInfo>[s_nLists];
  277. registeredCallbacksLists = Interlocked.CompareExchange(ref m_registeredCallbacksLists, list, null);
  278. if (registeredCallbacksLists == null) registeredCallbacksLists = list;
  279. }
  280.  
  281. //allocate the actual lists on-demand to save mem in low-use situations, and to avoid false-sharing.
  282. var callbacks = Volatile.Read<SparselyPopulatedArray<CancellationCallbackInfo>>(ref registeredCallbacksLists[myIndex]);
  283. if (callbacks == null)
  284. {
  285. SparselyPopulatedArray<CancellationCallbackInfo> callBackArray = new SparselyPopulatedArray<CancellationCallbackInfo>();
  286. Interlocked.CompareExchange(ref (registeredCallbacksLists[myIndex]), callBackArray, null);
  287. callbacks = registeredCallbacksLists[myIndex];
  288. }
  289.  
  290. // Now add the registration to the list.
  291. SparselyPopulatedArrayAddInfo<CancellationCallbackInfo> addInfo = callbacks.Add(callbackInfo);
  292. CancellationTokenRegistration registration = new CancellationTokenRegistration(callbackInfo, addInfo);
  293.  
  294. if (!IsCancellationRequested)
  295. return registration;
  296.  
  297. bool deregisterOccurred = registration.TryDeregister();
  298.  
  299. if (!deregisterOccurred)
  300. {
  301. return registration;
  302. }
  303. }
  304. // If cancellation already occurred, we run the callback on this thread and return an empty registration.
  305. callback(stateForCallback);
  306. return new CancellationTokenRegistration();
  307. }
  308.  
  309. public bool IsCancellationRequested
  310. {
  311. get { return m_state >= NOTIFYING; }
  312. }
  313.  
  314. internal bool IsCancellationCompleted
  315. {
  316. get { return m_state == NOTIFYINGCOMPLETE; }
  317. }
  318.  
  319. public CancellationToken Token
  320. {
  321. get
  322. {
  323. ThrowIfDisposed();
  324. return new CancellationToken(this);
  325. }
  326. }
  327. internal CancellationCallbackInfo ExecutingCallback
  328. {
  329. get { return m_executingCallback; }
  330. }
  331.  
  332. private static void LinkedTokenCancelDelegate(object source)
  333. {
  334. CancellationTokenSource cts = source as CancellationTokenSource;
  335. Contract.Assert(source != null);
  336. cts.Cancel();
  337. }
  338. }

CancellationTokenSource的实现相对比较复杂,我们首先看看CancellationTokenSource的构造函数,默认构造函数将会设置【m_state = NOT_CANCELED】,我们也可以构造一个特定时间后就自动Cancel的CancellationTokenSource,自动Cancel是依赖一个Timer实例,在Timer到指定时间后调用CancellationTokenSource的Cancel方法【这里是在TimerCallbackLogic里面调用Cancel方法】,CancelAfter方法的实现也是依赖这个Timer实例和TimerCallbackLogic方法。

现在我们来看看CancellationTokenSource最主要的一个方法Cancel,Cancel方法调用NotifyCancellation方法,NotifyCancellation方法主要调用ExecuteCallbackHandlers【从这个方法的名称可以猜测到主要是调用回调方法】,在ExecuteCallbackHandlers方法里面用到一个变量m_registeredCallbacksLists,它是SparselyPopulatedArray<CancellationCallbackInfo>[]结构,【可以理解为是一个链表的数组,数组每个元素时一个链表,链表里面的每个节点都可以访问下一个节点】,我们遍历这个链表数组的每一个节点,检查节点是否有值,即m_executingCallback != null,然后调用回调方法,如果回调方法的TargetSyncContext不为空,调用CancellationCallbackCoreWork_OnSyncContext方法,否者调用CancellationCallbackCoreWork方法【CancellationCallbackCoreWork_OnSyncContext里面也是调用它】,CancellationCallbackCoreWork方法是调用CancellationCallbackInfo的ExecuteCallback。

CancellationTokenSource有两个CreateLinkedTokenSource方法【可以理解为创建于当前的CreateLinkedTokenSource相关联的CreateLinkedTokenSource】,期主要实现是CancellationToken的Register方法。

  1. public struct CancellationToken
  2. {
  3. private CancellationTokenSource m_source;
  4. internal CancellationToken(CancellationTokenSource source)
  5. {
  6. m_source = source;
  7. }
  8. public CancellationToken(bool canceled) :this()
  9. {
  10. if(canceled)
  11. m_source = CancellationTokenSource.InternalGetStaticSource(canceled);
  12. }
  13.  
  14. public CancellationTokenRegistration Register(Action callback)
  15. {
  16. if (callback == null)
  17. throw new ArgumentNullException("callback");
  18.  
  19. return Register(s_ActionToActionObjShunt,callback,false,true);
  20. }
  21.  
  22. public CancellationTokenRegistration Register(Action callback, bool useSynchronizationContext)
  23. {
  24. if (callback == null)
  25. throw new ArgumentNullException("callback");
  26.  
  27. return Register(s_ActionToActionObjShunt,callback,useSynchronizationContext,true);
  28. }
  29.  
  30. public CancellationTokenRegistration Register(Action<Object> callback, Object state)
  31. {
  32. if (callback == null)
  33. throw new ArgumentNullException("callback");
  34.  
  35. return Register(callback,state,false,true);
  36. }
  37.  
  38. /// Registers a delegate that will be called when this CancellationToken is canceled.
  39. public CancellationTokenRegistration Register(Action<Object> callback, Object state, bool useSynchronizationContext)
  40. {
  41. return Register(callback,state,useSynchronizationContext,true);
  42. }
  43.  
  44. private CancellationTokenRegistration Register(Action<Object> callback, Object state, bool useSynchronizationContext, bool useExecutionContext)
  45. {
  46. StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
  47.  
  48. if (callback == null)
  49. throw new ArgumentNullException("callback");
  50.  
  51. if (CanBeCanceled == false)
  52. {
  53. return new CancellationTokenRegistration(); // nothing to do for tokens than can never reach the canceled state. Give them a dummy registration.
  54. }
  55.  
  56. SynchronizationContext capturedSyncContext = null;
  57. ExecutionContext capturedExecutionContext = null;
  58. if (!IsCancellationRequested)
  59. {
  60. if (useSynchronizationContext)
  61. capturedSyncContext = SynchronizationContext.Current;
  62. if (useExecutionContext)
  63. capturedExecutionContext = ExecutionContext.Capture(ref stackMark, ExecutionContext.CaptureOptions.OptimizeDefaultCase);
  64. }
  65.  
  66. // Register the callback with the source.
  67. return m_source.InternalRegister(callback, state, capturedSyncContext, capturedExecutionContext);
  68. }
  69.  
  70. private readonly static Action<Object> s_ActionToActionObjShunt = new Action<Object>(ActionToActionObjShunt);
  71. private static void ActionToActionObjShunt(object obj)
  72. {
  73. Action action = obj as Action;
  74. Contract.Assert(action != null, "Expected an Action here");
  75. action();
  76. }
  77.  
  78. public static CancellationToken None
  79. {
  80. get { return default(CancellationToken); }
  81. }
  82. public bool IsCancellationRequested
  83. {
  84. get
  85. {
  86. return m_source != null && m_source.IsCancellationRequested;
  87. }
  88. }
  89.  
  90. public bool CanBeCanceled
  91. {
  92. get
  93. {
  94. return m_source != null && m_source.CanBeCanceled;
  95. }
  96. }
  97. public void ThrowIfCancellationRequested()
  98. {
  99. if (IsCancellationRequested)
  100. ThrowOperationCanceledException();
  101. }
  102. private void ThrowOperationCanceledException()
  103. {
  104. throw new OperationCanceledException(Environment.GetResourceString("OperationCanceled"), this);
  105. }
  106. }

CancellationToken的很多属性都是来源于CancellationTokenSource的属性,CancellationToken的主要方法 Register 也是嗲用CancellationTokenSource的InternalRegister方法。InternalRegister方法检查当前是否发起了Cancel【IsCancellationRequested】,如果是直接调用回调方法callback(stateForCallback);,否者把回调方法包装成CancellationCallbackInfo实例,然后添加到m_registeredCallbacksLists对象中,然后在返回CancellationTokenRegistration实例。

  1. internal class CancellationCallbackInfo
  2. {
  3. internal readonly Action<object> Callback;
  4. internal readonly object StateForCallback;
  5. internal readonly SynchronizationContext TargetSyncContext;
  6. internal readonly ExecutionContext TargetExecutionContext;
  7. internal readonly CancellationTokenSource CancellationTokenSource;
  8.  
  9. internal CancellationCallbackInfo(Action<object> callback, object stateForCallback, SynchronizationContext targetSyncContext, ExecutionContext targetExecutionContext,CancellationTokenSource cancellationTokenSource)
  10. {
  11. Callback = callback;
  12. StateForCallback = stateForCallback;
  13. TargetSyncContext = targetSyncContext;
  14. TargetExecutionContext = targetExecutionContext;
  15. CancellationTokenSource = cancellationTokenSource;
  16. }
  17.  
  18. private static ContextCallback s_executionContextCallback;
  19. internal void ExecuteCallback()
  20. {
  21. if (TargetExecutionContext != null)
  22. {
  23. var callback = s_executionContextCallback;
  24. if (callback == null) s_executionContextCallback = callback = new ContextCallback(ExecutionContextCallback);
  25.  
  26. ExecutionContext.Run(TargetExecutionContext, callback, this);
  27. }
  28. else
  29. {
  30. ExecutionContextCallback(this);
  31. }
  32. }
  33.  
  34. private static void ExecutionContextCallback(object obj)
  35. {
  36. CancellationCallbackInfo callbackInfo = obj as CancellationCallbackInfo;
  37. Contract.Assert(callbackInfo != null);
  38. callbackInfo.Callback(callbackInfo.StateForCallback);
  39. }
  40. }
  41.  
  42. internal class SparselyPopulatedArray<T> where T : class
  43. {
  44. private readonly SparselyPopulatedArrayFragment<T> m_head;
  45. private volatile SparselyPopulatedArrayFragment<T> m_tail;
  46. internal SparselyPopulatedArray(int initialSize)
  47. {
  48. m_head = m_tail = new SparselyPopulatedArrayFragment<T>(initialSize);
  49. }
  50.  
  51. internal SparselyPopulatedArrayFragment<T> Tail
  52. {
  53. get { return m_tail; }
  54. }
  55.  
  56. internal SparselyPopulatedArrayAddInfo<T> Add(T element)
  57. {
  58. while (true)
  59. {
  60. // Get the tail, and ensure it's up to date.
  61. SparselyPopulatedArrayFragment<T> tail = m_tail;
  62. while (tail.m_next != null)
  63. m_tail = (tail = tail.m_next);
  64.  
  65. // Search for a free index, starting from the tail.
  66. SparselyPopulatedArrayFragment<T> curr = tail;
  67. while (curr != null)
  68. {
  69. const int RE_SEARCH_THRESHOLD = -; // Every 10 skips, force a search.
  70. if (curr.m_freeCount < )
  71. --curr.m_freeCount;
  72.  
  73. if (curr.m_freeCount > || curr.m_freeCount < RE_SEARCH_THRESHOLD)
  74. {
  75. int c = curr.Length;
  76. int start = ((c - curr.m_freeCount) % c);
  77. if (start < )
  78. {
  79. start = ;
  80. curr.m_freeCount--; // Too many free elements; fix up.
  81. }
  82. Contract.Assert(start >= && start < c, "start is outside of bounds");
  83.  
  84. // Now walk the array until we find a free slot (or reach the end).
  85. for (int i = ; i < c; i++)
  86. {
  87. // If the slot is null, try to CAS our element into it.
  88. int tryIndex = (start + i) % c;
  89. Contract.Assert(tryIndex >= && tryIndex < curr.m_elements.Length, "tryIndex is outside of bounds");
  90.  
  91. if (curr.m_elements[tryIndex] == null && Interlocked.CompareExchange(ref curr.m_elements[tryIndex], element, null) == null)
  92. {
  93. int newFreeCount = curr.m_freeCount - ;
  94. curr.m_freeCount = newFreeCount > ? newFreeCount : ;
  95. return new SparselyPopulatedArrayAddInfo<T>(curr, tryIndex);
  96. }
  97. }
  98. }
  99.  
  100. curr = curr.m_prev;
  101. }
  102.  
  103. // If we got here, we need to add a new chunk to the tail and try again.
  104. SparselyPopulatedArrayFragment<T> newTail = new SparselyPopulatedArrayFragment<T>(
  105. tail.m_elements.Length == ? : tail.m_elements.Length * , tail);
  106. if (Interlocked.CompareExchange(ref tail.m_next, newTail, null) == null)
  107. {
  108. m_tail = newTail;
  109. }
  110. }
  111. }
  112. }
  113.  
  114. internal struct SparselyPopulatedArrayAddInfo<T> where T : class
  115. {
  116. private SparselyPopulatedArrayFragment<T> m_source;
  117. private int m_index;
  118.  
  119. internal SparselyPopulatedArrayAddInfo(SparselyPopulatedArrayFragment<T> source, int index)
  120. {
  121. Contract.Assert(source != null);
  122. Contract.Assert(index >= && index < source.Length);
  123. m_source = source;
  124. m_index = index;
  125. }
  126.  
  127. internal SparselyPopulatedArrayFragment<T> Source
  128. {
  129. get { return m_source; }
  130. }
  131.  
  132. internal int Index
  133. {
  134. get { return m_index; }
  135. }
  136. }
  137.  
  138. internal class SparselyPopulatedArrayFragment<T> where T : class
  139. {
  140. internal readonly T[] m_elements; // The contents, sparsely populated (with nulls).
  141. internal volatile int m_freeCount; // A hint of the number of free elements.
  142. internal volatile SparselyPopulatedArrayFragment<T> m_next; // The next fragment in the chain.
  143. internal volatile SparselyPopulatedArrayFragment<T> m_prev; // The previous fragment in the chain.
  144.  
  145. internal SparselyPopulatedArrayFragment(int size) : this(size, null)
  146. {
  147. }
  148.  
  149. internal SparselyPopulatedArrayFragment(int size, SparselyPopulatedArrayFragment<T> prev)
  150. {
  151. m_elements = new T[size];
  152. m_freeCount = size;
  153. m_prev = prev;
  154. }
  155.  
  156. internal T this[int index]
  157. {
  158. get { return Volatile.Read<T>(ref m_elements[index]); }
  159. }
  160.  
  161. internal int Length
  162. {
  163. get { return m_elements.Length; }
  164. }
  165.  
  166. internal SparselyPopulatedArrayFragment<T> Prev
  167. {
  168. get { return m_prev; }
  169. }
  170.  
  171. internal T SafeAtomicRemove(int index, T expectedElement)
  172. {
  173. T prevailingValue = Interlocked.CompareExchange(ref m_elements[index], null, expectedElement);
  174. if (prevailingValue != null)
  175. ++m_freeCount;
  176. return prevailingValue;
  177. }
  178. }

回头看CancellationCallbackInfo的实现也很简单。

C# CancellationTokenSource和CancellationToken的实现的更多相关文章

  1. CancellationTokenSource 和 CancellationToken 取消线程

    Main 程序[分别调用三个方法] static void Main(string[] args) { using (CancellationTokenSource cts = new Cancell ...

  2. C#中CancellationToken和CancellationTokenSource用法

    之前做开发时,一直没注意这个东西,做了.net core之后,发现CancellationToken用的越来越平凡了. 这也难怪,原来.net framework使用异步的不是很多,而.net cor ...

  3. 在C#中使用 CancellationToken 处理异步任务

    在 .NET Core 中使用异步编程已经很普遍了, 你在项目中随处可见 async 和 await,它简化了异步操作,允许开发人员,使用同步的方式编写异步代码,你会发现在大部分的异步方法中,都提供了 ...

  4. 在ASP.NET Core中用HttpClient(五)——通过CancellationToken取消HTTP请求

    ​用户向服务器发送HTTP请求应用程序页面是一种非常可能的情况.当我们的应用程序处理请求时,用户可以从该页面离开.在这种情况下,我们希望取消HTTP请求,因为响应对该用户不再重要.当然,这只是实际应用 ...

  5. 浅谈C#取消令牌CancellationTokenSource

    前言 相信大家在使用C#进行开发的时候,特别是使用异步的场景,多多少少会接触到CancellationTokenSource.看名字就知道它和取消异步任务相关的,而且一看便知大名鼎鼎的Cancella ...

  6. C#CancellationToken/CancellationTokenSource-取消令牌/取消令牌源 CT/CTS

    详细情况:https://www.cnblogs.com/wucy/p/15128365.html 背景 为什么引入取消令牌? Thread.abort()方法会破坏同步锁中代码的原子逻辑,破坏锁的作 ...

  7. Asp.Net WebApi核心对象解析(下篇)

    在接着写Asp.Net WebApi核心对象解析(下篇)之前,还是一如既往的扯扯淡,元旦刚过,整个人还是处于晕的状态,一大早就来处理系统BUG,简直是坑爹(好在没让我元旦赶过来该BUG),队友挖的坑, ...

  8. .Net多线程编程—System.Threading.Tasks.Parallel

    System.Threading.Tasks.Parallel类提供了Parallel.Invoke,Parallel.For,Parallel.ForEach这三个静态方法. 1 Parallel. ...

  9. .Net多线程编程—任务Task

    1 System.Threading.Tasks.Task简介 一个Task表示一个异步操作,Task的创建和执行是独立的. 只读属性: 返回值 名称 说明 object AsyncState 表示在 ...

随机推荐

  1. Python题目练习(二)

    1.如何实现对python列表去重,并保持原来顺序 li = [1,2,5,3,1,6,3,8,0,3,2,4] l = [] for i in li: if i not in l: l.append ...

  2. java添加多个水印

    package com.zhx.util.imgutil; import com.zhx.util.stringutil.ArithUtil; import net.coobird.thumbnail ...

  3. Java 之 JavaScript (二)

    1.DOM a.作用:通过 HTML DOM,可访问 JavaScript HTML 文档的所有元素 b.功能: ①JavaScript 能够改变页面中的所有 HTML 元素 ②JavaScript ...

  4. TF:TF之Tensorboard实践:将神经网络Tensorboard形式得到events.out.tfevents文件+dos内运行该文件本地服务器输出到网页可视化—Jason niu

    import tensorflow as tf import numpy as np def add_layer(inputs, in_size, out_size, n_layer, activat ...

  5. 浅谈solr

    Solr是一个独立的企业级搜索应用服务器,它对外提供类似于Web-service的API接口.用户可以通过http请求,向搜索引擎服务器提交一定格式的XML文件,生成索引:也可以通过Http Get操 ...

  6. Windows下更改MySQL 数据库文件存放位置

    更改默认的mysql数据库目录 将 C:\Documents and Settings\All Users\Application Data\MySQL\MySQL Server 5.1\data 改 ...

  7. php include 绝对路径 dirname(__FILE__)

     include(dirname(__FILE__)."/PHPMailer/function.php"); 

  8. [ZOJ1482]Partitions

    [ZOJ1482]Partitions 题目大意: 给定一个\(n\times n(n\le3000)\)的\(\texttt 0/\texttt1\)矩阵,求去掉所有的\(1\)以后,矩阵被分成几个 ...

  9. [Codeforces896C] Willem, Chtholly and Seniorious (ODT-珂朵莉树)

    无聊学了一下珂朵莉树 珂朵莉树好哇,是可以维护区间x次方和查询的高效数据结构. 思想大致就是一个暴力(相对而言)的树形数据结构 lxl毒瘤太强了,发明了ODT算法(Old Driver Tree老司机 ...

  10. ironic驱动-IMPITool

    概述 IMPITool驱动是通过ipmitool工具来管理部署节点的,目前主要有两个驱动: agent_ipmitool pxe_ipmitool 配置驱动 要修改ironic支持的驱动需要修改配置文 ...