我有一个.Net(v4.0)Windows服务应用程序,它在开始时旋转一个tpl任务,执行某些长时间运行的活动,并且基本上保持应用程序的生命周期,并且因此使用TaskCreationOptions创建。 LongRunning 参数值。
每当服务停止并调用.OnStop()方法时,我 .Cancel()我在创建它时移交给工作任务的CancellationToken(Source)我希望它是 .OnlyOnCanceled(...)继续执行任务。
问题是,服务/流程在没有延续任务的情况下关闭而“完全” - 有时它会相当快地退出,有时会完全耗尽,有时则不会。
这对我来说有意义,因为那个特定的任务可能位于另一个线程而不是主线程上,因此无法“拖延”/阻止主要任务结束。
因为我在那个Windows服务应用程序中没有SynchronizationContext,所以我无法告诉延续任务在主线程上运行/所以我想知道: 我是怎么做的?< / p>
更准确地说,运行tpl任务处理应用程序关闭的最佳实践是什么?
答案 0 :(得分:3)
您必须等待OnStop
方法(或OnPause
和OnShutdown
)完成您的任务。
在OnStop
中你需要做大约20秒的时间。如果您认为您的线程不会在20秒内完成,则应致电RequestAdditionalTime
。一旦从OnStop
返回,您的服务流程就可以终止。
使用ContinueWith
将异步调用传递给它的委托,无论您是通过ExecuteSynchronously
还是使用SynchronizationContext
。只要ContinueWith
执行,假设它是OnStop
的最后一行,OnStop
返回并将控制权返回给SCN(好吧,ServiceBase
,但它会设置您的服务状态停止并将控制权返回给SCM,可能会终止你的过程。
ExecuteSynchronously
表示延续与其继续执行的任务同步运行。即在与任务相同的线程上运行(如果可能)。任务可能不在调用ContinueWith
的线程上运行(否则无法调用ContinueWith
)因此ExecuteSynchronusly
并不意味着同步拨打ContinueWith
。
您需要执行以下操作:
RequestAdditionalTime(TimeSpan.FromSeconds(30).Milliseconds);
cancellationToken.Cancel();
task.Wait();
在OnStop
中,Wait
表示在任务完成之前您不会退出OnStop
(或者需要超过30秒且您的流程终止)
答案 1 :(得分:1)
这是因为延续任务也以异步方式运行 。要阻止它,您需要指定task continuation option:
...
t.ContinueWith(ct => {...}, TaskContinuationOptions.ExecuteSynchronously);
答案 2 :(得分:0)
在延续上指定TaskContinuationOptions.ExecuteSynchronously
不会影响前提。如果你等待前面的,然后退出服务,你的继续可能仍然没有运行!
执行此操作的唯一方法是在从OnStop
返回之前等待继续任务完成。
答案 3 :(得分:0)
IME,为这项专门的工作开始一个新线程要简单得多。由于默认值为Background = false,因此CLR将在退出之前自动等待它完成(服务规则仍然适用)。
添加私人布尔停止;然后你的线程方法只需要做(while == false){DoStuff(); } DoStoppingStuff();
你的OnStop然后只设置stops = true,你的线程将退出while循环并执行你的停止代码:)
IME你不需要添加volatile,但你当然可以