0

I have a background worker that performs a time consuming task, but I'm having trouble with the cancelling issue because I can manage to only flag cancellation and not actually terminate the process. In order to solve it, I tried to put some check points in the heavy function that I want to exit , but it seems not quite efficient. my code looks like this :

in some points in the heavy function I put those 2 lines :

if (general.backgroundWorker1.CancellationPending)
{ 
   return;
}

private void button4_Click(object sender, EventArgs e) //button invokes heavy function
{
    if (!backgroundWorker1.IsBusy)
        backgroundWorker1.RunWorkerAsync();
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    heavyFunction(this);
    if (backgroundWorker1.CancellationPending)
    {
        e.Cancel = true;
        return;
    }
}

private void backgroundWorker1_RunWorkerCompleted_1(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Cancelled)
    {
        statusLabel.Text = "Status: cancelled";
    }
    else if (e.Error != null)
    {
        statusLabel.Text = "ERROR!";
    }
    else
    {
        some code;
    }
}

private void cancelSDoutLoop_Click(object sender, EventArgs e)
{
    if (backgroundWorker1.IsBusy)
    {
        backgroundWorker1.CancelAsync();
    }
}
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Jonathan
  • 99
  • 1
  • 8
  • 1
    What do you mean by "invoking cancellation" ? That is not a real term. – H H Jul 28 '17 at 06:21
  • is `general` the `Form` object that you pass into the method `heavyFunction` ? – Mong Zhu Jul 28 '17 at 06:26
  • yes, indeed. sorry for not clarifying – Jonathan Jul 28 '17 at 06:29
  • Checking for `CancellationPending` and returning is helpful only if that code _can execute_. Which it can't until your `heavyFunction(this)` call returns. You need to pass cancellation context (e.g. the `BackgroundWorker` object all the way down to every point where you want to be able to interrupt the worker. See marked duplicates for some discussion, as well as many other `BackgroundWorker` questions on Stack Overflow. – Peter Duniho Jul 28 '17 at 06:33
  • Closed as a dupe but as summary: Yes, cancellation has to be cooperative. Your code should not need it to be instantaneous. – H H Jul 28 '17 at 14:31

1 Answers1

0

Cancel can be a complicate function to implement and is often left as an afterthought.

If you want to cancel heavyFunction (which should be probably be longRunningFunction ;) it will have to become cancel aware. You said that you already put check points, which makes sense.

You can try to use more of cancellable method calls that accept a cancellation token. For example Task.Delay has two overloads:

Delay(TimeSpan)

and

Delay(TimeSpan, CancellationToken)

Another strategy is to split the method into smaller, shorter tasks.

Finally, the cancel operation doesn't have to instantaneous. You may end up with "Cancelling..." status that waits for a good moment to stop the job.

tymtam
  • 31,798
  • 8
  • 86
  • 126