私は、サービスが完全にシャットダウンできるように、渡されるキャンセルトークンを使用しています。このサービスには、他のサービスへの接続を試行し続けるロジックがあるため、トークンは、別のスレッドで実行されているこれらの再試行ループから抜け出すための良い方法です。私の問題は、内部再試行ロジックを持つサービスを呼び出す必要がありますが、再試行が失敗した場合は、設定された期間後に戻る必要があるということです。これを行うタイムアウトを備えた新しいキャンセルトークンを作成したいと思います。これの問題は、新しいトークンが「マスター」トークンにリンクされていないため、マスタートークンがキャンセルされても、タイムアウトするか接続が確立されて戻るまで、新しいトークンは引き続き有効です。マスタートークンがキャンセルされると、新しいトークンもキャンセルされるように、2つのトークンをリンクします。 CancellationTokenSource.CreateLinkedTokenSource
メソッドを使用してみましたが、新しいトークンがタイムアウトになると、マスタートークンもキャンセルされました。トークンで行う必要があることを行う方法はありますか、それとも再試行ロジックの変更が必要になりますか(おそらくこれを簡単に行うことができないでしょう)
これが私がやりたいことです:
マスタートークン–サービスが完全にシャットダウンできるように、さまざまな関数を渡して渡されます。一時トークン–単一の関数に渡され、1分後にタイムアウトするように設定されています
マスタートークンをキャンセルする場合は、一時トークンもキャンセルする必要があります。
一時トークンの有効期限が切れた場合、マスタートークンを取り消すことはできません。
CancellationTokenSource.CreateLinkedTokenSource
を使用したい。 「親」と「子」CancellationTokenSource
esを持つことができます。以下に簡単な例を示します。
var parentCts = new CancellationTokenSource();
var childCts = CancellationTokenSource.CreateLinkedTokenSource(parentCts.Token);
childCts.CancelAfter(1000);
Console.WriteLine("Cancel child CTS");
Thread.Sleep(2000);
Console.WriteLine("Child CTS: {0}", childCts.IsCancellationRequested);
Console.WriteLine("Parent CTS: {0}", parentCts.IsCancellationRequested);
Console.WriteLine();
parentCts.Cancel();
Console.WriteLine("Cancel parent CTS");
Console.WriteLine("Child CTS: {0}", childCts.IsCancellationRequested);
Console.WriteLine("Parent CTS: {0}", parentCts.IsCancellationRequested);
期待どおりの出力:
子CTSをキャンセル
子供CTS:真
親CTS:誤り親CTSをキャンセル
子供CTS:真
親CTS:真
CancellationToken
ではなくCancellationTokenSource
のみを使用している場合でも、リンクされたキャンセルトークンを作成することは可能です。単純にRegister
メソッドを使用して、(擬似)子のキャンセルをトリガーします。
var child = new CancellationTokenSource();
token.Register(child.Cancel);
CancellationTokenSource
で通常行うことなら何でもできます。たとえば、しばらくするとキャンセルでき、以前のトークンを上書きすることもできます。
child.CancelAfter(cancelTime);
token = child.Token;
i3arnonは既に回答済み なので、CancellationTokenSource.CreateLinkedTokenSource()
を使用してこれを行うことができます。タスク全体のキャンセルとタスク全体のキャンセルなしの子タスクのキャンセルを区別したい場合に、このようなトークンの使用方法のパターンを示したいと思います。
_async Task MyAsyncTask(
CancellationToken ct)
{
// Keep retrying until the master process is cancelled.
while (true)
{
// Ensure we cancel ourselves if the parent is cancelled.
ct.ThrowIfCancellationRequested();
var childCts = CancellationTokenSource.CreateLinkedTokenSource(ct);
// Set a timeout because sometimes stuff gets stuck.
childCts.CancelAfter(TimeSpan.FromSeconds(32));
try
{
await DoSomethingAsync(childCts.Token);
}
// If our attempt timed out, catch so that our retry loop continues.
// Note: because the token is linked, the parent token may have been
// cancelled. We check this at the beginning of the while loop.
catch (OperationCancelledException) when (childCts.IsCancellationRequested)
{
}
}
}
_
一時トークンの有効期限が切れた場合、マスタートークンを取り消すことはできません。
MyAsyncTask()
の署名はCancellationToken
ではなくCancellationTokenSource
を受け入れることに注意してください。このメソッドはCancellationToken
のメンバーにのみアクセスできるため、誤ってマスター/親トークンをキャンセルすることはできません。マスタータスクのCancellationTokenSource
ができるだけ少ないコードから見えるようにコードを整理することをお勧めします。ほとんどの場合、これは、CancellationTokenSource
への参照を共有する代わりに、メソッドに_CancellationTokenSource.Token
_を渡すことで実行できます。
私は調査していませんが、CancellationToken
にアクセスせずにCancellationTokenSource
を強制的にキャンセルするためのリフレクションなどの方法があるかもしれません。できれば不可能ですが、それが可能であれば、それは悪い習慣と見なされ、一般に心配することではありません。