23

結果に句を使用Cancellation.Registerするコードを見てきました:usingCancellationTokenRegistration

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

であることを確認する必要があると思いますDisposeIDisposable、なぜ実装しているのIDisposableでしょうか。どのリソースを解放する必要がありますか? それが持っている唯一の方法は平等です。

あなたがそれをしないDisposeとどうなりますか?あなたは何を漏らしますか?

4

2 に答える 2

22

CancellationTokenRegistration.Unregister()このパターンは、が自動的に呼び出されるようにする便利な方法です。これは、Stephen Toub のParallel Programming with .NETブログ投稿 (たとえば、こちら) でよく使用されます。

IDisposable を必ず Dispose する必要があると思いますが、なぜ IDisposable を実装しているのでしょうか? どのリソースを解放する必要がありますか? それが持っている唯一の方法は平等です。

IMO、これに対する最良の答えは、Microsoft の Mike Liddell による.NET 4 Cancellation Frameworkの投稿にあります。

コールバックが に登録されると、コールバックがまったく同じセキュリティ コンテキストで実行されるようCancellationTokenに、現在のスレッドがキャプチャされます。ExecutionContext現在のスレッドの同期コンテキストのキャプチャはオプションであり、必要に応じてオーバーロードを介して要求できますct.Register()。コールバックは通常保存され、キャンセルが要求されたときに実行されますが、キャンセルが要求された後にコールバックが登録されている場合、コールバックは現在のスレッドですぐに実行されるか、該当する場合は現在のスレッドを介して実行されSend()ます SynchronizationContext

コールバックが に登録されているCancellationToken場合、返されるオブジェクトはCancellationTokenRegistrationです。これは軽い構造体型でありIDiposable、この登録オブジェクトを破棄すると、コールバックが登録解除されます。Dispose()メソッドが返された後、登録されたコールバックが実行されておらず、その後開始されないことが保証さ れます。この結果 CancellationTokenRegistration.Dispose()、コールバックが現在実行中の場合はブロックする必要があります。したがって、登録されたすべてのコールバックは高速である必要があり、長時間ブロックされることはありません。

Mike Liddell による別の関連ドキュメントは、"Using Cancellation Support in .NET Framework 4" (UsingCancellationinNET4.pdf)です。

更新されました。これは参照ソースで確認できます

CancellationTokenSourceキャンセル コールバックはではなく に登録されることに注意することも重要CancellationTokenです。そのため、CancellationTokenRegistration.Dispose()スコープが正しく設定されていない場合、登録は親CancellationTokenSourceオブジェクトの存続期間中アクティブのままになります。これにより、非同期操作のスコープが終了したときに予期しないコールバックが発生する可能性があります。たとえば、次のようになります。

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したがって、 で使い捨てをスコープする(または で明示的にusing呼び出す) ことが重要です。CancellationTokenRegistration.Dispose()try/finally

于 2014-02-09T00:02:19.570 に答える