0

I'm developing an application which periodically polls a web service for some data. The application has to run as a Windows service, thus it has to be started and stopped in an asynchronous way. I'm using threading for this.

The main loop of the worker thread acts this way:

bool stop = false;
int interval = 60000;    // 60 seconds, customizable

while(!stop)
{
    try
    {
        // Query the web service using a WebRequest
    }
    catch(Exception e)
    {
        // Handle exception
    }

    // Process data

    try
    {
        Thread.Sleep(interval);
    }
    catch(ThreadInterruptedException)
    {}
}

To stop the worker thread, I do this from a controlling thread:

stop = true;
workerthread.Interrupt();
workerthread.Join();

This works perfectly... unless by chance the worker thread happens to be performing (or has yet to perform) a web request when Thread.Interrupt() is called; in this case, what gets actually interrupted is the web request (which presumably sleeps on its own), and the next Sleep() has to wait until its regular timeout to exit.

What is a better way to accomplish this and avoid interrupting the worker thread in the wrong place?

Massimo
  • 1,520
  • 1
  • 19
  • 36
  • If all your service does is sleep and poll periodically then it should be a scheduled task rather than a service. See [Programs are not cats](http://blog.mischel.com/2013/02/01/programs-are-not-cats/). – Jim Mischel Mar 19 '14 at 19:56

1 Answers1

2

Use a MaualResetEvent:

In the class that launches the thread:

ManualResetEvent evt = new ManualResetEvent(false);

Then modify your code to be:

int interval = 60000;    // 60 seconds, customizable

while(evt.WaitOne(interval))
{
    try
    {
        // Query the web service using a WebRequest
    }
    catch(Exception e)
    {
        // Handle exception
    }

    // Process data
}

To stop the thread, just call evt.Set();

This will cause the thread to stop even even if it is in the middle of the 60 second wait.

pquest
  • 3,151
  • 3
  • 27
  • 40
  • 1
    What happens if the worker thread is not waiting yet when calling `evt.Set()`? – Massimo Mar 19 '14 at 17:08
  • The next time it hits the top of the while loop it will stop immediately. Does each loop of your process take a long time? – pquest Mar 19 '14 at 17:13
  • No, at most a few seconds; it's ok to complete the running loop and exit when reaching the next WaitOne(). – Massimo Mar 19 '14 at 17:19
  • It works great, I've only moved the sleep at the bottom of the loop in order to have the first work cycle start immediately. – Massimo Mar 19 '14 at 17:28
  • you can also actually WaitOne for 0 ms. When I need to do that I usually define a bool to track if it is the first loop and then do `WaitOne(isFirst?0:interval)` – pquest Mar 19 '14 at 18:30
  • `while(true)` and then `if(WaitOne(interval)) break;` works equally well :) – Massimo Mar 19 '14 at 18:41