views:

31

answers:

1

I have a Windows service that has a number of threads that all need to be stopped before the service stops. I'm using this model for stopping my threads and signalling that they have been stopped:

ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
{
    Thread1Running = true;

    try
    {
        while (running)
        {
            AutoReset1.WaitOne(TimeSpan.FromSeconds(30.0));

            if (running)
            {
                // do stuff
            }
        }
    }
    finally
    {
        Thread1Running = false;
    }
}));

When it comes time to shut my service to stop, I just set running to false and call Set() on all the AutoResets out there. This instantly signals the threads to stop sleeping or to stop once they've finished processing what they're working on. This works really well. But, the part that I'm most nervous about, is verifying that everything has stopped. This is what I'm doing now:

Int32 tries = 0;
while (tries < 5 && (Thread1Running || Thread2Running || Thread3Running))
{
    tries++;

    Thread.Sleep(TimeSpan.FromSeconds(5.0));
}

The main reason that I don't like this is that it's time based, and if one of my threads is in the middle of a lengthy operation (which is quite likely), the shut down may not finish in that 25 seconds (and it's very important that all of these threads be shut down by the time OnStop, where this code gets run, finishes). I can't remove the tries because if one of those threads hangs (they don't, but you never know), then I'm really stuck and the service will never stop.

Is there a better way to do the verification that the threads have all stopped, preferably one that isn't time based? Or am I doomed to having some sort of timeout that might just need to be much longer (10 tries with a 30 second sleep, maybe)?

+1  A: 

I believe the general method for doing this is to join on the threads. The specifics of the call will depend on the threading library you're using, but in general the join method will block until the thread has exited (and should return immediately if the thread is already dead). So you could just join on all your threads in sequence, then exit. If all your joins have returned then all the threads have exited.

Many threading libraries allow you to add a timeout to join, which you would probably want to do. This way even if one of your threads hangs your exit code doesn't block.

Herms
Minor note. Before calling Join you should add call to RequestAdditionalTime otherwise the SCM will shut you down anyway
Conrad Frix
From his example code, it's clear that his threading library is the .net `System.Threading` namespace.
Reinderien
Thread.Join i a much better approach. Functionally it does the same thing that I'm doing, but it's much cleaner. It still suffers from being time based, but I can live with that. Any idea how I can use it with a ThreadPool? Or do I have to actually spawn threads?
Mike Pateras
Actually, I'd expect the ThreadPool should have a method on it you can use to block until its threads are shut down. At least the ones I'm used to (java) did.
Herms
Oh, and Join is actually a little different, at least from what I remember. It's cleaner in that it allows some extra cleanup to be done. At least from what I remember back when I was dealing with it (might be different in .Net with GC and such. I'm thinking back to my C days).
Herms