what's the proper way to tell a thread that is executing a loop to break out of the loop and do something else?

StackOverflow https://stackoverflow.com/questions/14528032

Pregunta

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)

¿Fue útil?

Solución

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)

Otros consejos

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top