You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用using处置CancellationTokenSource是否安全?代码实现是否正确?

这段代码存在线程安全隐患,你担心的问题确实可能发生!

你顾虑的场景完全是成立的——这是一个典型的竞态条件问题:

  1. 在CancelOperation()方法里,你刚做完_myCts != null的检查,此时它确实是非空状态;
  2. 就在这一瞬间,RunAsync()里的using块刚好执行完毕,_myCts被自动释放并置为null;
  3. 接着你执行_myCts.Cancel(),此时_myCts已经被释放,直接会抛出ObjectDisposedException。

怎么修复这个问题?

我们需要确保对_myCts的检查和取消操作是原子性的,不会被其他线程打断。这里给你两种常用的靠谱方案:

方案1:使用锁(Lock)实现同步

给_myCts的读写操作加锁,保证检查和Cancel操作是一个不可分割的整体:

private readonly object _ctsLock = new object();
CancellationTokenSource _myCts;

private async Task RunAsync() {
    using (var cts = CancellationTokenSource.CreateLinkedTokenSource(token1, token2)) {
        lock (_ctsLock) {
            _myCts = cts;
        }
        try {
            await DoWork();
        } finally {
            lock (_ctsLock) {
                _myCts = null;
            }
        }
    }
}

public void CancelOperation() {
    lock (_ctsLock) {
        _myCts?.Cancel();
    }
}

把_myCts的赋值、清空和取消操作都放在锁的保护下,就能彻底避免竞态条件的发生。

方案2:使用Interlocked原子操作(无锁方案)

如果对性能有要求,不想用锁,也可以用Interlocked类来原子地操作_myCts变量:

CancellationTokenSource _myCts;

private async Task RunAsync() {
    using (var cts = CancellationTokenSource.CreateLinkedTokenSource(token1, token2)) {
        // 原子替换旧的_myCts值为新创建的cts
        Interlocked.Exchange(ref _myCts, cts);
        try {
            await DoWork();
        } finally {
            // 只有当前cts还是_myCts的引用时,才将其置为null
            Interlocked.CompareExchange(ref _myCts, null, cts);
        }
    }
}

public void CancelOperation() {
    // 原子获取当前_myCts并将其置为null,再执行Cancel
    var cts = Interlocked.Exchange(ref _myCts, null);
    cts?.Cancel();
    // 注:这里不需要手动Dispose,因为RunAsync里的using块会负责释放
}

这种方式利用原子操作避免了锁的开销,适合对性能敏感的场景。

额外注意点

  • 不管用哪种方案,都不要在Cancel之后直接访问_myCts,因为它大概率已经被释放;
  • 一定要确保DoWork方法内部正确响应CancellationToken,否则Cancel操作根本不会生效。

内容的提问来源于stack exchange,提问作者Cadmi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 18:42:39