5

The following code has the disadvantage that the worker thread will neither terminate immediately nor perform a final action after the main thread resets the waithandle. Instead, it will continue doing what it is doing until it reaches the next iteration of the loop, at which point it will be blocked indefinitely.

static void Main()
{
 ManualResetEvent m = new ManualResetEvent(true); // or bool b = true
 Thread thread = new Thread(new ThreadStart(delegate()
 {
    while(m.WaitOne()) //or while(b)
    {
        //do something
    }
    //perform final operation and exit
 }));

 thread.Start();

 //do something

 m.Reset(); //or b = false

 //do something else
 }

The following code has the disadvantage that it uses the Abort() method (there are people who say it should be avoided at all costs), but accomplishes exactly what I'm looking for: force the worker thread to break out of the loop as soon as the main thread tells it to do so, perform a final operation, and exit.

static void Main()
{
 Thread thread = new Thread(new ThreadStart(delegate()
 {
    try
    {
        while(true)
        {
            //do something
        }
    }
    catch(ThreadAbortException e)
    {
           //perform final operation and exit
    }
 }));

 thread.Start();

 //do something

 thread.Abort();    

 //do something else
 }

Since neither solution is ideal, what's the proper way to implement the functionality I'm looking for?

(I'd prefer a solution that doesn't involve .net 4.5's tasks)

John Smith
  • 4,416
  • 7
  • 41
  • 56
  • If you can use .NET 4.5 take a look at Task (which provide a nice way of doing what you are trying to do). http://msdn.microsoft.com/en-us/library/dd537607.aspx – MattW Jan 25 '13 at 18:32

2 Answers2

1

If you cannot use .NET 4.5 (as I mentioned in a comment) then you could use a boolean value to cancel the looping. Here, I modified your second option:

static void Main()
{
    volatile bool keepGoing = true;

    Thread thread = new Thread(new ThreadStart(delegate()
    {
        while(keepGoing)
        {
            //do something
        }

        //logic to perform when the thread is cancelled
    }));

    thread.Start();

    //do something

    keepGoing = false; 

    //do something else
 }

Marking the bool value as volatile will ensure that you always have the correct value when checking it. This approach also ensures whatever action you were performing inside the loop is completed and not left in a "dirty" state.

http://msdn.microsoft.com/en-us/library/x13ttww7%28VS.80%29.aspx

MattW
  • 12,902
  • 5
  • 38
  • 65
  • 1
    the problem with this solution and the solution that uses the waithandle is that if the signal is sent while the worker is doing something, it won't stop doing it until it reaches the next iteration of the loop. I want the worker to exit the loop the moment the main thread tells it to do so. – John Smith Jan 25 '13 at 18:45
  • Ahh ok ... then the Background worker might be a better option. Tasks and CancellationTokens are nice if you can use them. – MattW Jan 25 '13 at 19:20
1

You can use a BackgroundWorker

static void Main()
{
    BackgroundWorker worker = new BackgroundWorker();
    worker.DoWork += worker_DoWork;
    worker.RunWorkerAsync();

    // do something 

    worker.CancelAsync();

    // do something else
}

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker worker = sender as BackgroundWorker;
    while(!worker.CancellationPending)
    {
        // do something
    }
    // perform final action
}

(Code is untested)

RobH
  • 3,604
  • 1
  • 23
  • 46
  • 1
    the problem with this solution and the solution that uses the waithandle is that if the signal is sent while the worker is doing something, it won't stop doing it until it reaches the next iteration of the loop. I want the worker to exit the loop the moment the main thread tells it to do so. – John Smith Jan 25 '13 at 18:46
  • @JohnSmith you can check to see if the operation is cancelled multiple times within the loop to give you more fine grained control of when to exit the loop. Why does it need to exit _immediately_? – RobH Jan 25 '13 at 18:53
  • 1
    @JohnSmith "I want the worker to exit the loop the moment the main thread tells it to do so" - there is no such thing. never was and never will.. regardless what .NET version. one or the other way (token or simple bool variable) - you thread is responsible to check if it can proceed or is time to exit...... – Boppity Bop Jan 31 '13 at 04:49