C# - 后台工作者的CancelAsync()不起作用?

时间:2013-08-19 13:21:08

标签: c# backgroundworker

我想中止该过程但不能这样做,我正在使用后台工作者处理我的功能。

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();
}

我无法使用此代码中止该过程。 函数abd()正在执行处理部分并返回结果。

请给我任何解决方案。

感谢。

4 个答案:

答案 0 :(得分:12)

当您致电bw.CancelAsync()时,您只需将CancellationPending标记设为true即可。默认情况下它不会取消某些内容。您需要手动处理待处理的取消。但是你不能用你的代码做到这一点,因为当你点击按钮时,有三种可能的选择:

  • 长时间运行的abd()方法完成了它的工作,没有什么可以取消
  • abd()启动它的工作,后台工作程序被阻止 - 它等待abd()的结果,然后继续执行 - 即退出if-else阻止并引发RunWorkerCompleted事件
  • 几乎不可能的选项 - 您将快速点亮,并在输入if-else块之前单击按钮。比CancellationPending为真,abd()不会开始执行

如果您想使用取消,请在循环中执行长时间运行的任务,并检查每个步骤是否有待取消:

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
}

答案 1 :(得分:1)

可能DoWork在调用CancelAsync之前可能已完成其工作,并且如文档e.Cancelled中所述可能是错误的。

Docs说这个

  

请注意,DoWork事件处理程序中的代码可能会完成   正在进行取消请求,以及您的轮询循环   可能会错过CancellationPending设置为true。在这种情况下,   取消了System.ComponentModel.RunWorkerCompletedEventArgs中的标志   即使您的RunWorkerCompleted事件处理程序也不会设置为true   虽然取消了请求。这种情况称为a   竞争条件,是多线程编程中常见的问题。

答案 2 :(得分:0)

以下情况如何?

While(!bw.CancellationPending)
{
   //do some work!
}
e.Cancel = true;

答案 3 :(得分:0)

函数abd()占用的处理时间过多,您想在两者之间中止处理。

private Thread _backgroundWorkerThread;

public void AbortBackgroundWorker()
{
    if(_backgroundWorkerThread != null)
    _backgroundWorkerThread.Abort();
}

void DoWork(object sender, DoWorkEventArgs e)
{
    try
    {
    _backgroundWorkerThread = Thread.CurrentThread;

    // call abd...

    }
    catch(ThreadAbortException)
    {
        // Do your clean up here.
    }
}

AbortBackgroundWorker()放入btncan_Click事件中。 但这要付出代价。现在,RunWorkerCompleted事件将不起作用。因此,您将不得不在catch块中处理它或编写我们自己的代码。