views:

200

answers:

3

I've got an abstract class that spawns an infinitely-looping thread in its constructor. What's the best way to make sure this thread is aborted when the class is done being used?

Should I implement IDisposable and simply this use this?

public void Dispose()
{
    this.myThread.Abort();
}

I read that Abort() is evil. Should I instead have Dispose() set a private bool flag that the thread checks for true to exit its loop?

public void Dispose()
{
    this.abort = true;
}

// in the thread's loop...

if (this.abort)
{
    break;
}

Use the BackgroundWorker class instead?

+3  A: 

Instead of having an infinite loop, use a boolean flag that can be set by the main class as the loop condition. When you're done, set the flag so the loop can gracefully exit. If you implement IDisposable, set the flag and wait for the thread to terminate before returning.

You could implement a cancellable BackgroundWorker class, but essentially it will accomplish the same thing.

If you really want, you can give it a window of time to finish itself after sending the signal. If it doesn't terminate, you can abort the thread like Windows does on shutdown.

The reason I believe Thread.Abort is considered "evil" is that it leaves things in an undefined state. Unlike killing an entire process, however, the remaining threads continue to run and could run into problems.

lc
Does C# not require any sort of memory barrier for such a flag?
bdonlan
It does. You need to use the "volatile" keyword. See my post below.
Scott Wisniewski
In practice, you'll see the flag value eventually even without volatile (at least on x86 and x64) -- it may take some time (several ms), but you'll see it. In theory though, Scott is right, volatile should actually be used here.
Jonathan
A: 

I'd suggest the BackgroundWorker method. It's relatively simple to implement and cleans up well.

McAden
+4  A: 

I would like to expand on the answer provided by "lc" (which is otherwise great).

To use his approach you also need to mark the boolean flag as "volatile". That will introduce a "memory barrier" which will ensure that each time your background thread reads the variable that it will grab it from memory (as opposed to a register), and that when the variable gets written that the data gets transfered between CPU caches.

Scott Wisniewski
+1 Very good point.
lc