1

I'm having trouble canceling a background worker that has a Thread.Sleep(100) in it.

private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
        int count;
        try
        {
            count = int.Parse(textBox3.Text);

            for (int i = 0; i < count; i++)
            {
                backgroundWorker1.ReportProgress((int)(((double)(i + 1) / count) * 1000));
                //Computation code
                Thread.Sleep(int.Parse(textBox4.Text));
            }
        }
        catch (Exception ex)
        {
            request.DownloadData(url);
            MessageBox.Show(ex.Message);
        }
}

private void cancel_Click(object sender, EventArgs e)
{
    backgroundWorker1.CancelAsync();
    progressBar1.Value = 0;
}

If I remove the Thread.Sleep(100) then the cancel works but otherwise it just keeps going (the progress bar doesn't stop).

EDIT: Added the rest of the code

Jack
  • 5,680
  • 10
  • 49
  • 74
  • 1
    Can you post the rest of the loop? Does it check some flag on each iteration? Does reducing the sleep time, say to 1 solve the problem? – Joey Oct 14 '11 at 10:22
  • that Sleep(100) is in processing loop? – Renatas M. Oct 14 '11 at 10:22
  • 1
    Incomplete code. Just the Sleep(100) call could only _delay_ cancelling a little. There must be something else. – H H Oct 14 '11 at 10:24
  • There was a similiar question on stackoverflow. See http://stackoverflow.com/questions/800767/how-to-kill-background-worker-completely – wlf84k Oct 14 '11 at 10:33
  • Well the only thing I added was put the Sleep(100) within a try-catch. – Jack Oct 14 '11 at 17:16
  • Ouch. You can't access textboxes from DoWork and you're main action is inside a catch? And there is no Cancel support in your DoWork. – H H Oct 15 '11 at 20:44

2 Answers2

6

When you call CancelAsync it just sets a property called CancellationPending to true. Now your backgroundworker can, and should, periodically check if this flag is true, to gracefully finish its operation. So you need to split your background task into pieces where you can check for cancelation.

private void DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
    {
        while(true)
        {
            if(worker.CancellationPending)
            {
                e.Cancel = true;
                return;
            }

            Thread.Sleep(100);
        }
    }
dowhilefor
  • 10,971
  • 3
  • 28
  • 45
0

Use Thread.Interrupt to exit from WaitSleepJoin state when you want to cancel the background thread.

http://msdn.microsoft.com/en-us/library/system.threading.thread.interrupt.aspx

mircea
  • 493
  • 3
  • 8
  • 2
    I think interrupting a thread is a bad thing to do if there is a more graceful way (i.e. using worker.CacellationPending). – Joey Oct 14 '11 at 10:27
  • Thread.Interrupt is just to exit from the sleep state when you want to cancel. After that, you catch ThreadInterruptedException and check for CancellationPending. – mircea Oct 14 '11 at 10:32
  • I would prefer making the sleep shorter so you don't have to worry about catching a `ThreadInterruptedException`. – Joey Oct 14 '11 at 10:35