7

我有一个 .Net (v4.0) Windows 服务应用程序,它在开始时旋转一个 tpl 任务,该任务执行某些长时间运行的活动,并且在应用程序的生命周期内基本上保持活动状态,因此是使用 TaskCreationOptions 创建的。LongRunning参数值。

每当服务停止并调用 .OnStop() 方法时,我在创建它时将.Cancel() CancellationToken(Source) 移交给工作任务,并且我希望它是.OnlyOnCanceled(...)延续任务跑。

问题是,服务/进程在没有“完全”运行的连续任务的情况下关闭 - 有时它退出相当快,有时它完全运行,有时它没有。

这对我来说确实有意义,因为该特定任务可能位于主线程之外的另一个线程上,因此无法“停止”/阻止该主线程结束。

由于我在该 Windows 服务应用程序中没有 SynchronizationContext 我无法告诉继续任务在那里/在主线程上运行,所以我想知道:我该怎么

更准确地说,在运行 tpl 任务时处理应用程序关闭的最佳实践是什么?

4

4 回答 4

3

OnStop您必须在方法(或OnPauseOnShutdown)中等待您的任务完成。

你有大约 20 秒的时间来做任何你需要的事情OnStop。如果你认为你的线程不会在 20 秒内完成,你应该调用RequestAdditionalTime. 只要您从OnStop服务中返回,进程就可以终止。

UsingContinueWith异步调用传递给它的委托,无论您是传递ExecuteSynchronously还是使用SynchronizationContext. 一旦ContinueWith执行,假设这是最后一行OnStopOnStop返回并将控制权返回给 SCN(好吧,ServiceBase但是它将您的服务状态设置为 STOPPED 并将控制权返回给 SCM 以可能终止您的进程。

ExecuteSynchronously意味着延续相对于它正在继续的任务同步运行。即在与任务相同的线程上运行(如果可能)。该任务可能不在正在调用的线程上运行ContinueWith(否则它无法调用ContinueWith),因此ExecuteSynchronusly对于对ContinueWith.

您需要执行以下操作:

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

in OnStop,这Wait意味着您在任务完成之前不会退出OnStop(或者它需要超过 30 秒并且您的进程被终止)

于 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 只需设置 stop = true ,您的线程将退出 while 循环并执行您的停止代码:)

IME 你不需要添加 volatile,但你当然可以

于 2012-08-25T14:46:52.960 回答