C# CancellationTokenSource和CancellationToken的实现

本文探讨了C#中CancellationTokenSource的实现细节,包括其构造函数、Cancel方法的工作原理,以及如何通过Timer实现自动Cancel。还介绍了CancellationToken的主要方法Register和属性,并分析了CancellationCallbackInfo在回调处理中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

public class CancellationTokenSource : IDisposable
{
    private const int CANNOT_BE_CANCELED = 0;
    private const int NOT_CANCELED = 1;
    private const int NOTIFYING = 2;
    private const int NOTIFYINGCOMPLETE = 3;
    
    private volatile int m_state;
    private static readonly Action<object> s_LinkedTokenCancelDelegate = new Action<object>(LinkedTokenCancelDelegate);    
    private static readonly int s_nLists = (PlatformHelper.ProcessorCount > 24) ? 24 : PlatformHelper.ProcessorCount; 
    private volatile CancellationCallbackInfo m_executingCallback;
    private volatile SparselyPopulatedArray<CancellationCallbackInfo>[] m_registeredCallbacksLists;
    private static readonly TimerCallback s_timerCallback = new TimerCallback(TimerCallbackLogic);
    private volatile Timer m_timer;
    
    public CancellationTokenSource()
    {
        m_state = NOT_CANCELED;
    }
    
    //Constructs a CancellationTokenSource that will be canceled after a specified time span.
    public CancellationTokenSource(Int32 millisecondsDelay)
    {
        if (millisecondsDelay < -1)
        {
            throw new ArgumentOutOfRangeException("millisecondsDelay");
        }

        InitializeWithTimer(millisecondsDelay);
    }
    
    private void InitializeWithTimer(Int32 millisecondsDelay)
    {
        m_state = NOT_CANCELED;
        m_timer = new Timer(s_timerCallback, this, millisecondsDelay, -1);
    }
    
    private static void TimerCallbackLogic(object obj)
    {
        CancellationTokenSource cts = (CancellationTokenSource)obj;
        if (!cts.IsDisposed)
        {            
            try
            {
                cts.Cancel(); // will take care of disposing of m_timer
            }
            catch (ObjectDisposedException)
            {
                if (!cts.IsDisposed) throw;
            }
        }
    }
    
    public void Cancel()
    {
        Cancel(false);
    }

    public void Cancel(bool throwOnFirstException)
    {
        ThrowIfDisposed();
        NotifyCancellation(throwOnFirstException);            
    }
    
    public void CancelAfter(Int32 millisecondsDelay)
    {
        ThrowIfDisposed();

        if (millisecondsDelay < -1)
        {
            throw new ArgumentOutOfRangeException("millisecondsDelay");
        }

        if (IsCancellationRequested) return;
        if (m_timer == null)
        {
            Timer newTimer = new Timer(s_timerCallback, this, -1, -1);
            if (Interlocked.CompareExchange(ref m_timer, newTimer, null) != null)
            {
                newTimer.Dispose();
            }
        }
        
        // It is possible that m_timer has already been disposed, so we must do
        // the following in a try/catch block.
        try
        {
            m_timer.Change(millisecondsDelay, -1);
        }
        catch (ObjectDisposedException)
        {        
        }
    }
    
   
    private void NotifyCancellation(bool throwOnFirstException)
    {
        if (IsCancellationRequested)
            return;

        // If we're the first to signal cancellation, do the main extra work.
        if (Interlocked.CompareExchange(ref m_state, NOTIFYING, NOT_CANCELED) == NOT_CANCELED)
        {
            Timer timer = m_timer;
            if(timer != null) timer.Dispose();

            //record the threadID being used for running the callbacks.
            ThreadIDExecutingCallbacks = Thread.CurrentThread.ManagedThreadId;
            
            //If the kernel event is null at this point, it will be set during lazy construction.
            if (m_kernelEvent != null)
                m_kernelEvent.Set(); // update the MRE value.

            ExecuteCallbackHandlers(throwOnFirstException);
            Contract.Assert(IsCancellationCompleted, "Expected cancellation to have finished");
        }
    }
    
    /// Invoke the Canceled event. The handlers are invoked synchronously in LIFO order.
    private void ExecuteCallbackHandlers(bool throwOnFirstException)
    {
        Contract.Assert(IsCancellationRequested, "
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值