7

最初に特定の長時間実行されるアクティビティを実行し、基本的にアプリケーションの存続期間中存続する tpl タスクをスピンする .Net (v4.0) Windows サービス アプリケーションがあり、TaskCreationOptions で作成されます。LongRunningパラメータ値。

サービスが停止し、.OnStop() メソッドが呼び出されるたびに、.Cancel()作成時にワーカー タスクに渡した CancellationToken(Source) を.OnlyOnCanceled(...)継続タスクにしたい走る。

問題は、その継続タスクが「完全に」実行されずにサービス/プロセスがシャットダウンすることです。かなり早く終了する場合もあれば、完全に終了する場合もあれば、終了しない場合もあります。

その特定のタスクはおそらくメインのスレッドとは別のスレッドにあるため、そのメインのタスクを「停止」/ブロックして終了させる方法がないため、これは私には理にかなっています。

そのWindowsサービスアプリケーションにSynchronizationContextがないので、その継続タスクをそこで/メインスレッドで実行するように指示できないので、どうすればよいのでしょうか?

より正確には、実行中の tpl タスクでアプリケーションのシャットダウンを処理するためのベスト プラクティスは何ですか?

4

4 に答える 4

3

OnStopメソッド(またはOnPauseおよび)でタスクが完了するのを待つ必要がありますOnShutdown

で必要なことは何でもするのに約20秒ありますOnStop。スレッドが20秒で完了すると思わない場合は、を呼び出す必要がありますRequestAdditionalTime。サービスから戻るとすぐに、OnStopプロセスを終了できます。

を使用ContinueWithすると、を渡すか使用するかに関係なく、渡されたデリゲートが非同期に呼び出されます。実行するとすぐに、それがの最後の行であると仮定して、制御をSCNに戻し、戻します(ただし、サービスの状態をSTOPPEDに設定し、制御をSCMに戻し、おそらくプロセスを終了します。ExecuteSynchronouslySynchronizationContextContinueWithOnStopOnStopServiceBase

ExecuteSynchronously継続は、継続しているタスクに関して同期的に実行されることを意味します。つまり、タスクと同じスレッドで実行します(可能な場合)。タスクは、呼び出しているスレッドで実行されていないContinueWith可能性があります(そうでない場合は呼び出すことができませんでしたContinueWith)。したがってExecuteSynchronusly、への呼び出しに関して同期的であることを意味するわけではありませんContinueWith

次のようなことをする必要があります。

RequestAdditionalTime(TimeSpan.FromSeconds(30).Milliseconds);
cancellationToken.Cancel();
task.Wait();

OnStop、タスクが完了するまで(または30秒以上かかり、プロセスが終了するまで)Wait終了しないことを意味しますOnStop

于 2012-08-25T14:26:04.007 に答える
1

これは、継続タスクも非同期で実行されるために発生します。ブロックするには、タスク継続オプションを指定する必要があります。

...
t.ContinueWith(ct => {...}, TaskContinuationOptions.ExecuteSynchronously);
于 2012-08-25T09:13:31.113 に答える
0

継続を指定TaskContinuationOptions.ExecuteSynchronouslyしても、先行詞には影響しません。先行詞を待ってからサービスを終了すると、継続が実行されない可能性があります。

これを行う唯一の方法は、から戻る前に継続タスクが完了するのを待つことですOnStop

于 2012-08-25T11:50:54.050 に答える
0

私見、これはTPLの使用には不向きです。タスクは、この種の「永久に実行」ロジックを対象としたものではありません。

IME、この専用の作業のために新しいスレッドを開始する方がはるかに簡単です。デフォルトはBackground=falseであるため、CLRは自動的に完了するのを待ってから終了します(サービスルールは引き続き適用されます)。

プライベートブール停止を追加します。次に、スレッドメソッドはwhile(stopping == false){DoStuff();を実行する必要があります。} DoStoppingStuff();

次に、OnStopはstopping = trueを設定するだけで、スレッドはwhileループを終了し、停止コードを実行します:)

IME揮発性物質を追加する必要はありませんが、確かに可能です。

于 2012-08-25T14:46:52.960 に答える