Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C#- background worker's CancelAsync() not working?

I want to abort the process but not able to do so, I am using Background worker with my functions of processing.

public void Init()
{
    bw = new BackgroundWorker();
    bw.WorkerSupportsCancellation = true;
    bw.DoWork += new DoWorkEventHandler(bw_DoWork);
    bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
}

void bw_DoWork(object sender, DoWorkEventArgs e)
{
    if (bw.CancellationPending == true)
    {
        e.Cancel = true;
    }
    else
    {
        e.Result = abd();
    }
}

void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if(e.Cancelled)
    {
        lbltext.content="Canceled";
    }

    else
    {
        lbltext.content="Completed";
    }
}

private void btncan_Click(object sender, RoutedEventArgs e)
{
    bw.CancelAsync();
}

private void btnstart_Click(object sender, RoutedEventArgs e)
{
    bw.RunWorkerAsync();
}

I am not able to abort the process using this code. Function abd() is performing the processing part and returning the result.

Please provide me any solution.

Thanks.

like image 735
Neel Bhasin Avatar asked Aug 19 '13 13:08

Neel Bhasin


2 Answers

When you call bw.CancelAsync() you just set CancellationPending flag to true. It does not cancels something by default. You need to handle pending cancellation manually. But you can't do that with your code, because when you click button, there are three possible options:

  • Long-running abd() method finished it's work and there is nothing to cancel
  • abd() started it's work, and background worker is blocked - it's waiting for results of abd(), then it continues execution - i.e. exits if-else block and raises RunWorkerCompleted event.
  • Nearly impossible option - you will be fast as light, and you will click button before if-else block entered. Than CancellationPending will be true, and abd() will not start execution

If you want to use cancellation, then do your long-running task in a loop, and check if cancellation is pending on each step:

void bw_DoWork(object sender, DoWorkEventArgs e)
{
    List<Foo> results = new List<Foo>();

    // any loop here - foreach, while
    for(int i = 0; i < steps_count; i++)
    {    
         // check status on each step
         if (bw.CancellationPending == true) 
         {
             e.Cancel = true;
             return; // abort work, if it's cancelled
         }

         results.Add(abd()); // add part of results
    }

    e.Result = results; // return all results
}
like image 62
Sergey Berezovskiy Avatar answered Sep 24 '22 16:09

Sergey Berezovskiy


Probably DoWork may have finished its work before calling CancelAsync and as mentioned in the docs e.Cancelled may be false..

Docs say this

Be aware that your code in the DoWork event handler may finish its work as a cancellation request is being made, and your polling loop may miss CancellationPending being set to true. In this case, the Cancelled flag of System.ComponentModel.RunWorkerCompletedEventArgs in your RunWorkerCompleted event handler will not be set to true, even though a cancellation request was made. This situation is called a race condition and is a common concern in multithreaded programming.

like image 40
Anirudha Avatar answered Sep 22 '22 16:09

Anirudha