为什么CancellationTokenRegistration存在,为什么它实现IDisposable

为什么CancellationTokenRegistration存在,为什么它实现IDisposable

问题描述:

我已经看到了使用code Cancellation.Register 与上一个使用条款 CancellationTokenRegistration 结果:

I've been seeing code that uses Cancellation.Register with a using clause on the CancellationTokenRegistration result:

using (CancellationTokenRegistration ctr = token.Register(() => wc.CancelAsync()))
{
    await wc.DownloadStringAsync(new Uri("http://www.hamster.com"));
}

我得到你应该确保你处置的IDisposable ,但为什么它甚至农具的IDisposable ?它有什么样的资源来释放?唯一的方法,它考虑的平等。

I get that you should make sure you Dispose an IDisposable, but why does it even implements IDisposable? what resources does it have to release? The only methods it has regard equality.

如果你不是处置这会发生什么?你怎么泄露?

What happens if you don't Dispose of it? what do you leak?

此模式是一种简便的方法,以确保 CancellationTokenRegistration.Unregister()被自动调用。它经常在他与.NET 的博客文章,如并行编程here.

This pattern is a convenient way to make sure CancellationTokenRegistration.Unregister() is called automatically. It's often used by Stephen Toub in his Parallel Programming with .NET blog posts, e.g. here.

我得到你应该确保你处置了IDisposable的,但为什么   确实它甚至实现IDisposable?它有什么样的资源来   推出?唯一的方法,它考虑的平等。

I get that you should make sure you Dispose an IDisposable, but why does it even implements IDisposable? what resources does it have to release? The only methods it has regard equality.

IMO,这个最好的答案都可以在 .NET 4中微软的迈克·利德尔取消框架后:

IMO, the best answer to this can be found in the .NET 4 Cancellation Framework post by Microsoft's Mike Liddell:

在回调注册到的CancellationToken,目前   线程的执行上下文被捕获,使得回调将运行   具有完全相同的安全上下文。的捕获   当前线程的同步上下文是可选的,可以要求   通过ct.Register过载(),如果需要的话。回调是正常   存储并运行时取消请求,但如果一个回调   取消后注册已提出要求,回调将   紧接在当前线程上的当前运行,或通过发送()   如果适用的SynchronizationContext。

When a callback is registered to a CancellationToken, the current thread's ExecutionContext is captured so that the callback will be run with the the exact same security context . The capturing of the current thread's synchronization context is optional can be requested via an overload of ct.Register() if required. Callbacks are normally stored and then run when cancellation is requested, but if a callback is registered after cancellation has been requested, the callback will run immediately on the current thread, or via Send() on the current SynchronizationContext if applicable.

在回调注册到的CancellationToken,返回   对象是一个CancellationTokenRegistration。这是一个轻结构类型   这是IDiposable,和处理此登记对象使   回调被注销。一个作出保证,此前   Dispose()方法返回时,注册的回调既不是   运行也将随之展开。这方面的一个后果是,   CancellationTokenRegistration.Dispose()必须阻止如果回调   当前执行的。因此,所有注册的回调应该是快   并不会阻止任何显著的持续时间。

When a callback is registered to a CancellationToken, the returned object is a CancellationTokenRegistration. This is a light struct type that is IDiposable, and disposing this registration object causes the callback to be deregistered. A guarantee is made that after the Dispose() method has returned, the registered callback is neither running nor will subsequently commence. A consequence of this is that CancellationTokenRegistration.Dispose() must block if the callback is currently executing. Hence, all registered callbacks should be fast and not block for any significant duration.

由迈克·利德尔另一个相关的文件是"Using取消支持在.NET框架4(UsingCancellationinNET4.pdf)。

Another relevant document by Mike Liddell is "Using Cancellation Support in .NET Framework 4" (UsingCancellationinNET4.pdf).

更新,这是可核查的here在参考源。

同样重要的是要注意,取消回调注册的 CancellationTokenSource ,无法与的CancellationToken 。所以,如果 CancellationTokenRegistration.Dispose()不正确的范围,登记将保持活跃父的生命周期 CancellationTokenSource 对象。这可能会导致意想不到的回调,异步操作的范围已经结束,如:

It's also important to note, the cancellation callback is registered with the CancellationTokenSource, not with CancellationToken. So, if CancellationTokenRegistration.Dispose() is not correctly scoped, the registration will remain active for the lifetime of the parent CancellationTokenSource object. This may lead to an unexpected callback when the scope of the async operation is over, e.g.:

async Task TestAsync(WebClient wc, CancellationToken token)
{
    token.Register(() => wc.CancelAsync());
    await wc.DownloadStringAsync(new Uri("http://www.hamster.com"));
}

// CancellationTokenSource.Cancel() may still get called later,
// in which case wc.CancelAsync() will be invoked too

因此​​,重要的是要范围的一次性 CancellationTokenRegistration 使用(或叫 CancellationTokenRegistration .Dispose()明确地尝试/终于)。

Thus, is important to scope the disposable CancellationTokenRegistration with using (or call CancellationTokenRegistration.Dispose() explicitly with try/finally).