views:

462

answers:

3

I'm having a small background thread which runs for the applications lifetime - however when the application is shutdown, the thread should exit gracefully.

The problem is that the thread runs some code at an interval of 15 minutes - which means it sleeps ALOT.

Now in order to get it out of sleep, I toss an interrupt at it - my question is however, if there's a better approach to this, since interrupts generate ThreadInterruptedException.

Here's the gist of my code (somewhat pseudo):

public class BackgroundUpdater : IDisposable
{
    private Thread myThread;
    private const int intervalTime = 900000; // 15 minutes
    public void Dispose()
    {
        myThread.Interrupt();
    }

    public void Start()
    {
        myThread = new Thread(ThreadedWork);
        myThread.IsBackground = true; // To ensure against app waiting for thread to exit
        myThread.Priority = ThreadPriority.BelowNormal;
        myThread.Start();
    }

    private void ThreadedWork()
    {
        try
        {
            while (true)
            {
                Thread.Sleep(900000); // 15 minutes
                DoWork();
            }
        }
        catch (ThreadInterruptedException)
        {
        }
    }
}
+3  A: 

There's absolutely a better way - either use Monitor.Wait/Pulse instead of Sleep/Interrupt, or use an Auto/ManualResetEvent. (You'd probably want a ManualResetEvent in this case.)

Personally I'm a Wait/Pulse fan, probably due to it being like Java's wait()/notify() mechanism. However, there are definitely times where reset events are more useful.

Your code would look something like this:

private readonly object padlock = new object();
private volatile boolean stopping = false;

public void Stop() // Could make this Dispose if you want
{
    stopping = true;
    lock (padlock)
    {
        Monitor.Pulse(padlock);
    }
}

private void ThreadedWork()
{
    while (!stopping)
    {
        DoWork();
        lock (padlock)
        {
            Monitor.Wait(padlock, TimeSpan.FromMinutes(15));
        }
    }
}

For more details, see my threading tutorial, in particular the pages on deadlocks, waiting and pulsing, the page on wait handles. Joe Albahari also has a tutorial which covers the same topics and compares them.

I haven't looked in detail yet, but I wouldn't be surprised if Parallel Extensions also had some functionality to make this easier.

Jon Skeet
You are too fast. I give up ;)
frast
Great solution, thanks a lot :-)
Steffen
Isn't the problem here that the working thread is waiting while holding the lock, so that lock in stop() method would block for up to 15 minutes until the working thread releases the lock?
Tomáš Kafka
Won't that thread be locked for 15 minutes?
Svish
@Svish - Joe Albahari's tutorial explains this rather well - `Wait` actually unlocks the object while waiting for the pulse. I find this pattern to be rather unreadable for those not familiar with this `Wait` behaviour.
romkyns
A: 

One method might be to add a cancel event or delegate that the thread will subscribe to. When the cancel event is invoke, the thread can stop itself.

Chris Thompson
+1  A: 

You could use an Event to Check if the Process should end like this:

var eventX = new AutoResetEvent(false);
while (true)
{
    if(eventX.WaitOne(900000, false))
    {
        break;
    }
    DoWork();
}
frast