如何使用线程使 Win 服务长期运行

发布于 2024-09-11 18:55:43 字数 2158 浏览 8 评论 0原文

我有一个 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

我家小可爱 2024-09-18 18:55:43

首先,对于长时间运行的线程,创建自己的 Thread 对象并启动它;不要使用ThreadPool。线程池是为小型、相对短暂的操作而设计的。

其次,有多种方法可以使线程保持活动状态。最基本的是您尝试过的,这是一个 while 循环,最后有一个 sleep (或其他阻塞)调用。这是最基本的,但不一定是“最好的”。还有其他选项,例如可以从其他应用程序访问的命名 WaitHandle 对象,可以允许更具确定性的代码执行和更少的唤醒检查睡眠迭代。

但是,如果您无法(或不想)修改其他进程来支持向您的服务通知特定事件,那么您所拥有的本质上是正确的。不过,我鼓励选择更合理的睡眠时间;您真的需要每毫秒检查一次吗?

First, for a long-running thread, create your own Thread object and start it; don't use the ThreadPool. 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 named WaitHandle 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?

最好是你 2024-09-18 18:55:43

我通过使用 OnStart() 启动 System.Timers.Timer 解决了长时间运行的 Windows 服务的问题,并在计时器的 中执行所有处理ElapsedEventHandler

在处理程序内,我停止计时器,在单独的线程上执行工作,检查停止信号,然后在可以继续的情况下重新启动计时器。该服务的 OnStop() 方法会停止计时器并终止所有活动的工作线程。

工作线程处理所有异常,因此如果出现问题,它会记录异常、终止,然后在下一个计时器间隔重新启动。服务核心从未崩溃过。

I solved that problem with my very long running Windows service by having OnStart() launch a System.Timers.Timer, and do all of the processing in the timer's ElapsedEventHandler.

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.

浅黛梨妆こ 2024-09-18 18:55:43

关于阻塞,您可能应该使用等待/脉冲编程范例来指示一个线程继续。或者只是加入线程。

等待& 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#

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文