6

私は現在、次々に実行される一連のタスクを作成するアプリケーションを持っており、タスク間の実行を中断できるキャンセル ソースを使用します (つまり、安全な終了ポイントで)。現在、このキャンセル ソースは、管理クラスが Disposed の場合にのみ使用します。 、クリーンかつ迅速に実行を中止する方法として。

オペレーターがタイムリーに応答しない場合に備えて、自動タイムアウトを作成してタスク シーケンスをキャンセルするユース ケースがあります (一部のタスクは、物理メカニズムとのオペレーターの対話を待機します)。同時に、管理クラスが Disposed の場合はキャンセルをサポートする必要があります。CancellationTokenSource.CreateLinkedTokenSourceを見つけました。これは必要なように思えますが、いくつか懸念事項があります。

  1. 複数のタスク シリーズを並行して実行できるため、タイムアウトのキャンセル用に新しい CancellationTokenSource を作成し、開始する各タスク シリーズに関連するリンクされたソースを作成する必要があります。CancellationTokenSource は IDisposable を実装しています。つまり、最後のタスクが完了したとき、またはサブタスクのいずれかが Canceled または Faulted になったときに、両方のキャンセル ソースを保持して Dispose する必要があります。これは、匿名メソッド クロージャの便利な魔法を使用しても、かなりぎこちないように思えます (これらのキャンセル ソースはまだ渡されています)。

  2. また、タイマーが切れる前にキャンセル ソースが破棄される状態から保護する必要があります (したがって、破棄されたソースをキャンセルしません)。これは競合状態になる可能性があるため、適切なロックを追加する必要があります。これも厄介なようで、かなりの複雑さ (将来のメンテナンス コスト) が追加され、単体テストがより困難になります (競合状態を確実に誘発するのは難しいです)。

ここで正しい道を進んでいますか、それとももっと簡単な方法がありますか?

4

1 に答える 1

9

あなたの質問の中心的な問題は、あなたやオブジェクトの呼び出しDispose()に関連しているようです。この場合、これらを呼び出さないことをお勧めします。これにより、設計が大幅に簡素化されます。TaskCancellationTokenSourceDispose

正当化として、このスレッドを参照します。特に、Stephen Toub(タスクを担当するPM)は、次のことを提案しています。

コードの構造に基づいて実行するのが簡単で正しい場合は、積極的に破棄してください。破棄するために奇妙な回転を行う必要がある場合(またはタスクの場合は、追加の同期を使用して安全に破棄できるようにします。破棄はタスクが完了した後にのみ使用できるため)、ファイナライズに依存する方がよいでしょう。物事の世話をします。

これは彼が最後に説明している正確な状況のように聞こえます-あなたはDispose()これらのオブジェクトを呼び出すために奇妙な旋回を行おうとしています。

于 2011-06-07T17:21:55.720 に答える