c# - CreateLinkedTokenSource 抛出 ObjectDisposedException。如何正确安全地处置 CancellationTokenSource?

标签 c# .net multithreading async-await

之前在这里问过很多类似的问题。

MSDN 指出 one should always dispose the CancellationTokenSource when done with it 作为重要说明.

好的,但是对于多线程应用程序和异步等待模型,它会变得有点复杂。

我正在开发一个库。我遇到的问题是我在多个地方使用 CreateLinkedTokenSource 从用户那里收到的 CancellationToken。很快,我这样做是为了能够在操作花费的时间超过某个时间时自行取消操作。

例子

public async Task<Result> DoAsync(CancellationToken cancellationToken)
{ 
    using (var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken)) 
    {
        // here pass linkedTokenSource.Token further down the line 
        var resultTask = sender.DoAsync(linkedTokenSource.Token); 
        var timeoutTask = Task.Delay(timeout); 
        var completed = await Task.WhenAny(resultTask, timeoutTask); 
        if (completed  == timeoutTask) 
        {
            linkedTokenSource.Cancel(); 
            throw TimeoutException(); 
        }

        return await resultTask;
        // from the point of view of this piece of code
        // we're done with the cancellationTokenSource right? 
        // so I need to dispose the source (done here via `using`)
    }
}

然而,在不同的代码部分,由于竞争条件,有些线程正试图从 linkedTokenSource.TokenCreateLinkedTokenSource 导致 code>ObjectDisposedException 因为 linkedTokenSourceTimeoutException 被抛出后已经被释放。
这将以 UnobservedTaskException 结束,如果用户监听未观察到的异常,这将使用户感到困惑。

在每个 CreateLinkedTokenSource 上放置一个 try-catch 并使 ObjectDisposedException 行静音对我来说似乎又很奇怪。

我的问题是:

  1. 为什么 CreateLinkedTokenSource 抛出这个异常?对此有解释吗?由于 CencellationToken 是一个结构,为什么我不能从中创建新的源? (即使在 cancellationToken 被取消)。

  2. 对于在这种情况下应该如何处理处置有什么建议吗?

最佳答案

This will end up in a UnobservedTaskException which will confuse the user if he listens on unobserved exceptions.

嗯,有点。 UnobservedTaskException 几乎总是在您使用 Task.WhenAny 时成为现实(并放弃未完成的任务,这是绝大多数时间 Task.WhenAny 被使用)。

因此,他们可能会收到 ObjectDisposedException 报告给 UnobservedTaskException 而不是 OperationCanceledException。嗯;在 async 世界中,如果您正在使用 Task.WhenAny,您确实需要忽略 UnobservedTaskException。此外,许多“不容易取消”的端点将关闭取消请求的基础句柄,这无论如何都会导致 (IIRC) ObjectDisposedException

Why the CreateLinkedTokenSource throws this exception? Is there an explanation for this?

它是那些really, really old Microsoft design guidelines that were written with an '80s OOP mindset的一部分.我从不同意 MS 的 Dispose 指南,更喜欢 much simpler model它涵盖了所有相同的用例,并且精神开销显着减少。

Any suggestions on how should handle disposing in this scenario?

保持原样。 UnobservedTaskException 没什么大不了的。

关于c# - CreateLinkedTokenSource 抛出 ObjectDisposedException。如何正确安全地处置 CancellationTokenSource?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37441215/

相关文章:

c# - 插入数据库时​​如何以编程方式覆盖 Auto_Increment 值

c# - 为什么我无法在 .Net 中使用 AWS SES 接收电子邮件

c++ - 如何获得 future 值(value)?

c# - 保证TransformBlock输出顺序

c# - 动态禁用特定的上下文菜单项

c# - asp.net - 绑定(bind)到 linq 数据源并添加外部列

c# - 如何告诉nuget将包资源文件添加为链接,而不是将它们复制到项目目录中

主线程异常上的android os网络

c# - 使用 LINQ 断言数组的所有成员都是等效的?

.net - 如何在 .NET 类的方法和属性中注入(inject)管道代码?