複数のキャンセル待ち
async/awaitで非同期のコードを書いているとCancellationTokenを良く使う。
複数のCancellationTokenを使う場合、「すべて」のキャンセルを待機するにはCancellationTokenSource#CreateLinkedTokenSource()を使えばいいらしいが、「いずれか」のキャンセルを待機する仕組みがないようなので作ってみた。
#2013/08/15追記
CancellationTokenSource#CreateLinkedTokenSource()は引数に指定した「いずれかの」Tokenのキャンセル待ちのために使用できます。
日本語のMSDNには一部「すべての」という記述がありますが誤訳と思われます。
英語のMSDNを確認してください。
public class MultiCancellationToken : IDisposable { private List<CancellationTokenRegistration> _cancellationTokenRegistrationList = new List<CancellationTokenRegistration>(); private CancellationTokenSource _cts = new CancellationTokenSource(); private bool _disposed; public MultiCancellationToken(params CancellationToken[] tokens) { foreach (var token in tokens) { _cancellationTokenRegistrationList.Add(token.Register(() => { Cancel(); })); } } private void Cancel() { lock (this) { if (_cts.IsCancellationRequested) { return; } _cts.Cancel(); foreach (var token in _cancellationTokenRegistrationList) { token.Dispose(); } _cancellationTokenRegistrationList.Clear(); } } public CancellationToken Token { get { return _cts.Token; } } protected void Dispose(bool dispose) { if (!dispose || _disposed) { return; } _disposed = true; lock (this) { foreach (var token in _cancellationTokenRegistrationList) { token.Dispose(); } _cancellationTokenRegistrationList.Clear(); _cts.Dispose(); } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } ~MultiCancellationToken() { Dispose(false); } }
c#のDisposeの流儀がいまいちわかってない・・・