【发布时间】:2016-05-25 15:12:36
【问题描述】:
这里之前已经提出了多个类似的问题。
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.Token 中取出CreateLinkedTokenSource,从而导致ObjectDisposedException,因为linkedTokenSource 已经在之后被释放TimeoutException 被抛出。
这将以UnobservedTaskException 告终,如果用户侦听未观察到的异常,这将使用户感到困惑。
在每个CreateLinkedTokenSource 上加上try-catch 并让ObjectDisposedException 行静音对我来说似乎又很奇怪。
我的问题是:
-
为什么
CreateLinkedTokenSource会抛出这个异常?对此有解释吗?既然CencellationToken是一个结构,为什么我不能从中创建一个新的源? (即使在cancelToken被取消)。 -
关于在这种情况下应该如何处理的任何建议?
【问题讨论】:
-
最近在 GitHub 的 CoreClr 存储库中对此进行了讨论。在这些情况下,行为已更改为不引发异常。此更改尚未在 Desktop CLR 中。在某个地方,在触发 .NET 修复的 Stack Overflow 上有一个重复的问题。
-
正如@usr 所说,这是为.NET Core 修复的。只想添加问题链接:github.com/dotnet/coreclr/issues/4167。 Stephen Toub 是个英雄!
标签: c# .net multithreading async-await