应用程序停用时BackgroundWorker线程的接近程度如何?

时间:2011-10-01 12:02:03

标签: c# multithreading windows-phone-7 backgroundworker windows-phone-7.1

我使用BackgroundWorker创建线程,并且在循环中我每次检查CancellationPending是否为真,如下所示:

   public MainPage()
    {
        InitializeComponent();

        bw = new BackgroundWorker();
        bw.WorkerReportsProgress = true;
        bw.WorkerSupportsCancellation = true;
        bw.DoWork += new DoWorkEventHandler(bw_DoWork);
        bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
        bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
    }

    private void ButtonStart_Click(object sender, RoutedEventArgs e)
    {
        if (bw.IsBusy != true)
        {
            bw.RunWorkerAsync();
        }
    }

    private void ButtonCancel_Click(object sender, RoutedEventArgs e)
    {
        if (bw.WorkerSupportsCancellation)
        {
            bw.CancelAsync();
        }
    }

    private void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;

        for (int i = 1; i <= 100; i++)
        {
            Debug.WriteLine("The tread is working");
            if (worker.CancellationPending)
            {
                e.Cancel = true;
                bw.CancelAsync();
                break;
            }
            else
            {

                System.Threading.Thread.Sleep(500);
                worker.ReportProgress(i);
            }
        }
    }

    private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Cancelled)
        {
            tbProgress.Text = "Canceled";
        }
        else if (e.Error != null)
        {
            tbProgress.Text = "Error: " + e.Error.Message;
        }
        else
        {
            tbProgress.Text = "Done";
        } 
    }

    private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        tbProgress.Text = e.ProgressPercentage.ToString() + "%";
    }

当取消激活应用程序时,线程未关闭,它被中止并发生异常。应用程序停用时与BackgroundWorker的线程有多接近?

4 个答案:

答案 0 :(得分:10)

当一个应用程序被停用时,主UI线程以外的每个线程一旦激活就会抛出一个ThreadAbortException。这似乎是“按设计”作为一种迫使应用程序快速停止他们正在做的事情的方式。线程可以捕获ThreadAbortException并包装它们正在做的事情,但要注意ThreadAbortException将在catch块的末尾再次自动引发。 finally块中的任何代码也将被执行。

对于您的特定问题,在停用应用程序时没有理由尝试取消BackgroundWorker,因为ThreadAbortException将发生并将有效地停止后台工作程序。如果你想在发生这种情况时做一些事情来清理,你可以在bw_DoWork中捕获ThreadAbortException,做你需要做的事情,然后让它死掉。

要在激活后重新启动它,您必须重新启动后台工作程序,就像第一次运行应用程序时一样。

答案 1 :(得分:5)

您是否将BackgroundWorker设置为可取消?

 var bg= new BackgroundWorker();
 bg.WorkerSupportsCancellation = true;

来自文档:

  

如果希望BackgroundWorker支持取消,请将WorkerSupportsCancellation属性设置为true。如果此属性为true,则可以调用CancelAsync方法来中断后台操作。

此外,您的代码似乎有误,您应该在线程代码之外调用CancelAsync(),这将设置可用于退出循环的CancellationPending标志。

虽然我不是100%肯定,因为我不知道bw变量的来源。 `

答案 2 :(得分:2)

如果设置了标志,则应检查worker方法中的CancellationPending标志并正常退出 取消工作的条件是什么?取消按钮单击?然后你应该在那里放置CancelAsync(...)。它将为你已经在代码中检查的设置CancellationPending标志,避免需要类似ResetEvent对象的东西。

答案 3 :(得分:1)

我想根据自己的观察,在上面的答案中加上一个澄清点。 后台线程在保留实例时停用/激活

我的代码看起来像这样:

private void Application_Activated(object sender, ActivatedEventArgs e)
{
    if (e.IsApplicationInstancePreserved)
    {
        Log.write("Activating, instance preserved");
        // restart long-running network requests
        startBackground();
    }
    else // start over again
    {
        AppSettings.init();
        Log.write("Activating, rehydrating" );
        startBackground();
    }
}

我还记录了BackgroundWorker对象执行时的哈希码。我看到的是,每当我收到“激活,保存实例”消息时,我都会额外运行BackgroundWorker

基于此,似乎更准确地说线程在逻辑删除时中止,而不是在停用时?