2012-05-24 22 views
10

私のアプリケーションが凍結した後、Task.Delay()(または.NET 4.0のTaskEx.Delay())によって作成されたタスクを待っているスレッドの原因を追跡しました。そのために、TimeSpanが計算されたTimeSpanが発生しました。 TotalMilliseconds-1以下であり、-2より大きい(すなわち、-10000〜-19999ティックの間の任意の場所)。なぜTask.Delay()は無限の遅延を許しますか?

設定することで、(あなたが-2ミリ秒以下である負TimeSpan通過したときに、この方法が正しくArgumentOutOfRangeException投げていますが、上記の範囲からの負のTimeSpanを提供する場合、それが完了したことがないTask返すことが表示されます下にあるSystem.Threading.TimerからdueTimeの-1は無限大を表す)。つまり、そのタスクに設定された継続は決して実行されず、にある.Wait()に起こった貧弱なスレッドは永遠にブロックされます。

完了していないTaskには、どのような可能性がありますか?誰もそのような戻り値を期待するだろうか?その特別な範囲の値を含む、負の値が.Delay()に渡されるべきでない場合は、ArgumentOutOfRangeExceptionを投げる?

+1

MSDNのドキュメントでは-1を明示的に使用しているため、正しく動作しているようです。そのオーバーロードのユースケースについては不明ですが、キャンセルトークンを使用するオーバーロードによる「キャンセル」のキャンセルを待つ方法になる可能性があります。 –

+0

@James:-1を明示的に指定するのではなく、-1より小さい値を許可しないことは明白です。 'System.Threading.Timer'のドキュメンテーションとは異なり、-1を渡すと何が起こるかは言いません。文書化された例外リストがソースコードから自動的に生成されたようです。そして、あなたが 'キャンセル'を待っているなら、なぜ 'Task.Delay()'を呼び出すのですか? –

+0

あなたはそれが壊れていると思ったら、接続時にバグを報告してください。 "-1より小さい"と書かれた文書は、-1が有効であると言って明白です(私に)。インテントが-1だった場合、無効な「0未満は無効です」と書く方が簡単でした。ドキュメントとコードの両方で-1が許されているので、これはBy Designだと思うが、BCLチームがランダムなSOスレッドよりも処理する可能性が高いので、バグをファイルに残すように気をつけてください:) –

答えて

7

Timeout.Infiniteまたは-1は、実行に不確定な時間がかかりますが最終的に完了する長期実行タスクが無期限に待機する場合に便利です。

また、Win32 APIでは、INFINITE = -1という無限のタイムアウトを使用します。

通常はUIスレッドで使用することは望ましくありません。これはUIをフリーズする可能性があります(これは問題のようです)。しかし、ワーカースレッドでは有効なユースケースが存在します。クライアントからの接続を待機しているサーバー。

+0

無限のタイムアウトが便利です。無限の遅延はありません(したがって、最初の段落は適用されません)。あなたは永遠に何をやりたいのですか?あなたはそれを実行しないでください。 '-1'の実装の詳細が' System.Threading.Timer'(またはWin32タイマー)から 'Task.Delay()'メソッドまで伝播するということは私には分かりません。私が気づいていないユースケースがない限り、開発者を「成功のピット」に押し込むというMicrosoftの設計原則に反する。 –

+0

また、UIスレッドで使用していません。停止するように要求されたときに、[TAP](http://www.microsoft.com/japan/windowsserver2003/downloads/details.aspx?id=19957)に基づく方法でシャットダウンルーチンを実行する必要があるWindowsサービスです実行には時間がかかりすぎるため、強制的なシャットダウンを実行する遅延タスクも作成されます。次に、両方のタスクで '.WaitAny()'を実行し、元のタスクが非常に長い時間を要し、(例外をスローするのではなく)遅延タスクが決して完了しないため、サービスがハングアップしたように見えます。 –

+1

クライアントからの接続を待っているサーバをブロックする方法は、決して完了しない 'Task'を使うでしょうか?例を見せてもらえますか? –

2

Task.WhenAny()ブロック内のコードが正しく待っているタスクの1つを処理していることを確認したい模擬シナリオで、私は他のタスクを模擬し、無限の遅延を使用してタスク。私が無限の遅れとして嘲笑しなかった仕事を、誰かが処理しています。

+2

興味深いユースケースですが、 'new TaskCompletionSource()。Task'を使用して無限のタスクを提供する方がより明白で明確になると思います。 –

関連する問題