views:

104

answers:

4

In case of BackgroundWorker, a cancel can be reported by the e.Cancel - property of the DoWork - event handler.

How can I achieve the same thing with a Thread object?

+4  A: 

Generally you do it by the thread's execute being a delegate to a method on an object, with that object exposing a Cancel property, and the long-running operation periodically chercking that property for tru to determine whether to exit.

for example

public class MyLongTunningTask
{
   public MyLongRunninTask() {}
   prop bool Cancel {get; set; }

   public void ExecuteLongRunningTask()
   {
     while(!this.Cancel)
     {
         // Do something long running.
        // you may still like to check Cancel periodically and exit gracefully if its true
     }
   }
}

Then elsewhere:

var longRunning = new MyLongTunningTask();
Thread myThread = new Thread(new ThreadStart(longRunning.ExecuteLongRunningTask));

myThread.Start();

// somewhere else
longRunning.Cancel = true;
Jamiec
You need to put volatile on the Cancel member to indicate that it will be changed from another thread.
adrianm
Well spotted. Should have added that.
Jamiec
A: 

A blocked thread can be stopped prematurely in one of two ways:

  • Thread.Interrupt

  • Thread.Abort

The main question is if the thread works on any ressources which need to be released correctly - in this case - you need to work with a property on the actual object which runs the thread.

weismat
Releasing resources need not be a problem, if the thread uses 'try ... finally' and/or 'using'
Tim Robinson
Everybody is arguing against Interrupt and Abort, so don't use them. http://msdn.microsoft.com/en-us/library/system.threading.thread.abort.aspx
Henk Holterman
A: 

There's Thread.Abort, which works by injecting a ThreadAbortException into the thread. It's a little risky because:

  1. Your thread can get stuck if it's executing native code at the time
  2. The code in the thread better be exception-safe, because this ThreadAbortException could happen on any line of code within it, even something innocent like i = i + 1

You're better off coding your own signalling mechanism between your GUI thread and the background thread. It's hard to recommend something without knowing what's going on inside that thread, but where I have a thread that works by waiting on some object in a loop, I use an AutoResetEvent and wait on that too.

Tim Robinson
It's not a little risky, it's wrong.
Henk Holterman
I'm reluctant to call some part of the .NET framework (like the `Thread.Abort` method) wrong outright; I just keep a mental list of techniques to avoid.
Tim Robinson
+4  A: 

Here is a full example of one way of doing it.

private static bool _runThread;
private static object _runThreadLock = new object();

private static void Main(string[] args)
{
    _runThread = true;
    Thread t = new Thread(() =>
    {
        Console.WriteLine("Starting thread...");
        bool _localRunThread = true;
        while (_localRunThread)
        {
            Console.WriteLine("Working...");
            Thread.Sleep(1000);
            lock (_runThreadLock)
            {
                _localRunThread = _runThread;
            }
        }
        Console.WriteLine("Exiting thread...");
    });
    t.Start();

    // wait for any key press, and then exit the app
    Console.ReadKey();

    // tell the thread to stop
    lock (_runThreadLock)
    {
        _runThread = false;
    }

    // wait for the thread to finish
    t.Join();

    Console.WriteLine("All done.");    
}

In short; the thread checks a bool flag, and keeps runing as long as the flag is true. I prefer this approach over calling Thread.Abort becuase it seems a bit nicer and cleaner.

Fredrik Mörk
Nice, although it's better if you can code it in terms of `WaitHandle` rather than polling. Of course this depends on how the code inside the thread works.
Tim Robinson
@Tim: yes, a WaitHandle would probably be a cleaner approach rather than relying on a shared field as in my example. That would remove the need for locking as well, making the code a bit more to the point.
Fredrik Mörk