之前在这里已经问过多个类似的问题。
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`)
}
}
但是,由于竞争条件的缘故,在不同代码段中,由于某些线程正在尝试从
CreateLinkedTokenSource
中删除linkedTokenSource.Token
,从而导致生成ObjectDisposedException
,因为在抛出linkedTokenSource
之后已经处理掉了TimeoutException
。这将以
UnobservedTaskException
结尾,如果用户监听未观察到的异常,将会使用户感到困惑。对我来说,在每个
try-catch
上放一个CreateLinkedTokenSource
并使ObjectDisposedException
行静音似乎又很奇怪。我的问题是:
CreateLinkedTokenSource
抛出此异常?请问对此有解释吗?由于CencellationToken
是一个结构,为什么我不能从中创建新的源代码? (甚至在cancelToken中也被取消)。 最佳答案
好吧,有点。每当您使用UnobservedTaskException
时,Task.WhenAny
几乎总是生活中的事实(并且放弃不完整的任务,这是Task.WhenAny
使用的绝大部分时间)。
因此,他们可能会收到报告给ObjectDisposedException
的UnobservedTaskException
而不是OperationCanceledException
的信息。 h在async
世界中,如果您使用的是Task.WhenAny
,则无论如何,您确实确实需要忽略UnobservedTaskException
。此外,许多“不容易取消”的端点将在取消请求时关闭底层句柄,这无论如何都会导致(IIRC)ObjectDisposedException
。
它是这些really, really old Microsoft design guidelines that were written with an '80s OOP mindset的一部分。我从未同意MS的Dispose指南,而是希望使用much simpler model来涵盖所有相同的用例,而所需的精神开销却大大减少。
保持原样。 UnobservedTaskException
没什么大不了的。
关于c# - CreateLinkedTokenSource引发ObjectDisposedException。如何正确安全地配置CancellationTokenSource?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37441215/