How to make a Win Service run Long Term with Threa

2019-04-10 18:18发布

问题:

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?

回答1:

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?



回答2:

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.



回答3:

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#