如何使用线程使 Win 服务长期运行
我有一个 win 服务托管一些我需要保持长时间运行的工作流程(一个 WorkflowApplication 和一个 WorkflowServiceHost)。因为 OnStart() 要求它完成并返回操作系统,所以我有一个在线程池中的另一个线程上触发的 main 方法。我的 Onstart() 主要看起来像这个
protected override void OnStart(string[] args)
{
eventLog.WriteEntry("Service starting...");
ThreadPool.QueueUserWorkItem(new WaitCallback(ServiceMainThread));
Thread.Sleep(100);
eventLogCms.WriteEntry("Service Started.");
}
ServiceMainThread() 是我的工作流程执行和实现核心功能的方法。当我在 Windows 7 计算机上启动该服务时,它会运行,然后在大约 8 分钟后终止。在 Win Server 2008 上,线程永远不会执行。
所以我认为我错误地实现了线程,并且 ServiceMainThread
有点不稳定。由于我是 .Net 中线程的新手,因此我愿意接受有关可以改进的内容或任何方向的建议。 ServiceMainThread 中的基本线程代码是这样编码的:
private void ServiceMainThread(object state)
{
// .. execute workflows ..
eventLog.WriteEntry("Workflows executed.");
while(alive)
{
Thread.Sleep(1);
// ... check workflow states and ensure they're still executing ...
}
// .. halt workflow executions and perform persist operations if necessary ..
eventLog.WriteEntry("Workflows halted.");
}
为了充分说明目的,这里是我的 OnStop() 实现:
protected override void OnStop()
{
alive = false;
this.haltEvent.WaitOne(); // haltEvent is of type ManualResetEvent
}
有什么明显的我可以更改以使我的工作流长期保持在执行状态吗? while 循环似乎有点太老套了(更不用说我不喜欢将线程延迟任何时间),而且我确信可能有更好的解决方案。
使用线程而不是线程池确实可以正常启动,但它似乎允许工作流程在执行开始之前运行 2 分钟,并且停止现在已损坏,但我认为我也许能够纠正 OnStop()。当我这样做时,我将 ServiceMainThread() 中的 while 循环设置为空块,这样它就不会阻塞正在执行工作流的线程。
更新: 我在事件日志中从 .Net 收到此异常:
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.NullReferenceException
Stack:
at Ptm.ServiceMainThread()
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
at System.Threading.ThreadHelper.ThreadStart()
Server 2008 是 64 位,这可能与我的问题有关吗?
I have a win service hosting a few workflows (a WorkflowApplication and a WorkflowServiceHost) that I need to keep long running. Because OnStart() requires that it completes and returns to the OS, I have a main method that fires on another thread in a threadpool. My Onstart() mainly looks like this
protected override void OnStart(string[] args)
{
eventLog.WriteEntry("Service starting...");
ThreadPool.QueueUserWorkItem(new WaitCallback(ServiceMainThread));
Thread.Sleep(100);
eventLogCms.WriteEntry("Service Started.");
}
ServiceMainThread() is the method where my workflows execute and core functionality is implemented. When I start the service on my Windows 7 machine it runs and then dies after approximately 8 minutes. On Win Server 2008, the thread NEVER executes.
So I think I've implemented threading incorrectly and what's ServiceMainThread
is a bit shakey. I'm open to suggestions to what could be improved or any direction as I'm new to threading in .Net. Basic threading code in ServiceMainThread is coded as such:
private void ServiceMainThread(object state)
{
// .. execute workflows ..
eventLog.WriteEntry("Workflows executed.");
while(alive)
{
Thread.Sleep(1);
// ... check workflow states and ensure they're still executing ...
}
// .. halt workflow executions and perform persist operations if necessary ..
eventLog.WriteEntry("Workflows halted.");
}
And for full illustrative purposes here is my OnStop() implementation:
protected override void OnStop()
{
alive = false;
this.haltEvent.WaitOne(); // haltEvent is of type ManualResetEvent
}
Is there anything obvious that I could change to make my workflows remain in the execution state long term? The while loop seems a little too hackish (not to mention I don't like having to delay the thread for any amount of time as it is) and I'm sure there may be a better solution.
Using a Thread instead of a thread pool did ok starting but it seemed to allow the workflow run for 2minutes before execution started and stopping is now broken but I think I may be able to correct OnStop(). When I did that I set the while loop in ServiceMainThread() to an empty block so it doesn't block the thread the workflows are executing on.
Update:
I get this exception from .Net in event logs:
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.NullReferenceException
Stack:
at Ptm.ServiceMainThread()
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
at System.Threading.ThreadHelper.ThreadStart()
Server 2008 is 64-bit, could that have something to do with my issue?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
首先,对于长时间运行的线程,创建自己的 Thread 对象并启动它;不要使用
ThreadPool
。线程池是为小型、相对短暂的操作而设计的。其次,有多种方法可以使线程保持活动状态。最基本的是您尝试过的,这是一个
while
循环,最后有一个 sleep (或其他阻塞)调用。这是最基本的,但不一定是“最好的”。还有其他选项,例如可以从其他应用程序访问的命名WaitHandle
对象,可以允许更具确定性的代码执行和更少的唤醒检查睡眠迭代。但是,如果您无法(或不想)修改其他进程来支持向您的服务通知特定事件,那么您所拥有的本质上是正确的。不过,我鼓励选择更合理的睡眠时间;您真的需要每毫秒检查一次吗?
First, for a long-running thread, create your own
Thread
object and start it; don't use theThreadPool
. The thread pool is designed for small, relatively short-lived operations.Second, there are several ways that you can keep your thread alive. The most basic is what you've tried, which is a
while
loop with a sleep (or other blocking) call at the end. This is the most basic, though not necessarily the "best". There are other options, like namedWaitHandle
objects that can be accessed from other applications, that can allow for more deterministic code execution and fewer iterations of wake-check-sleep.If, however, you either can't (or don't want to) modify the other processes to support notifying your service of particular events, then what you have is, essentially, correct. I would, however, encourage selecting a more reasonable
Sleep
time; do you really need to check every millisecond?我通过使用
OnStart()
启动System.Timers.Timer
解决了长时间运行的 Windows 服务的问题,并在计时器的中执行所有处理ElapsedEventHandler
。在处理程序内,我停止计时器,在单独的线程上执行工作,检查停止信号,然后在可以继续的情况下重新启动计时器。该服务的
OnStop()
方法会停止计时器并终止所有活动的工作线程。工作线程处理所有异常,因此如果出现问题,它会记录异常、终止,然后在下一个计时器间隔重新启动。服务核心从未崩溃过。
I solved that problem with my very long running Windows service by having
OnStart()
launch aSystem.Timers.Timer
, and do all of the processing in the timer'sElapsedEventHandler
.Inside the handler I stop the timer, do the work on separate threads, check for a halt signal, and then restart the timer if it's OK to continue. The service's
OnStop()
method stops the timer and kills any active worker threads.The worker threads handle all exceptions, so if one has a problem, it logs the exception, terminates, and then gets restarted on the next timer interval. The service core has never crashed.
关于阻塞,您可能应该使用等待/脉冲编程范例来指示一个线程继续。或者只是加入线程。
等待& Pulse - C# 中的线程
In regards to your blocking, you should probably use a Wait/Pulse Programming paradigm for signalling one thread to continue. Or to just Join the thread.
Wait & Pulse - Threading in C#