Search code examples
c#windows-servicesmanualresetevent

windows service using shutdown event cant stop the service


I've written a windows service that attempts to read messages from an MSMQ and process them. I have added an installer to my project, and I have set the startup to manual. I install the service and then start it through the Services tool. I can then go back to my project and attach to the process to step through the code.

However, regardless of what I do, I cannot stop the service either in code or from the Services tool. I can only think that it's because I'm using a ManualResetEvent Class to control the service. Here's my code. I'm trying to test the Error section since at this point it should throw an error and stop the service.

In my service class I have:

private readonly ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
    private Thread _thread;

    public TestService()
    {
        InitializeComponent();
    }

    protected override void OnStart(string[] args)
    {
        _thread = new Thread(WorkerThread)
        {
            Name = "Test Messaging Reader Service Thread",
            IsBackground = true
        };
        _thread.Start();

    }

    protected override void OnStop()
    {
        _shutdownEvent.Set();
        if (!_thread.Join(3000))
        { // give the thread 3 seconds to stop
            _thread.Abort();
        }
        IError logger = new Logger();
        Exception ex = new Exception("The Test Messaging Service has been stopped.");
        logger.Log(this, SeverityEnum.Warning, ex);
    }

    private void WorkerThread()
    {
        try
        {

            while (!_shutdownEvent.WaitOne(0))
            {
                TestMessageQueueReader processQueue = new TestMessageQueueReader();
                processQueue.ReadFromQueue();
                _shutdownEvent.Set();
                _shutdownEvent.Reset();
            }
        }
        catch (Exception)
        {

            _shutdownEvent.Set();
            _shutdownEvent.Close();
        }

    }

When I step through the code it does drop into the exception as expected, at which point I'd expect to be able to stop the service.


Solution

  • The worker thread is resetting the event immediately before testing it:

            while (!_shutdownEvent.WaitOne(0))
            {
                // ...
                _shutdownEvent.Reset();
            }
    

    That means that unless the stop request comes in at exactly the right time, it will be ignored.

    Instead, the loop should look like this:

            while (!_shutdownEvent.WaitOne(0))
            {
                TestMessageQueueReader processQueue = new TestMessageQueueReader();
                processQueue.ReadFromQueue();
            }
    

    You also shouldn't be closing the event from the worker thread, because the other threads may still need it. (The event will be automatically closed when the process exits, so you don't need to worry about it.)

    As for the exception handling, you can't make the service stop simply by setting the event. If there is more than one worker thread, setting the event will stop them, but not the service itself. I'm not entirely sure how you make a .NET service stop itself, but try calling ServiceBase.Stop.