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