【问题标题】:BackgroundWorker cancellationBackgroundWorker 取消
【发布时间】:2015-01-21 18:14:05
【问题描述】:

我在我的 winforms 应用程序中使用 BackgroundWorker 来执行另一个类中发生的长时间运行的任务(执行数据库操作)。由于所有工作都在另一个类中完成,因此取消并不那么简单。我正在使用另一个类 (GenerateStats) 中的事件来更新后台操作完成时的进度。我想通过取消操作来做类似的事情。我不能只在 DoWork 函数中调用cancellationPending,因为该方法在完成之前永远不会看到它,这违背了目的。我想要取消功能,而无需将 BackgroundWorker 传递给generateForSubject()。无论如何,这可以支持从GenerateStats 类中的generateForSubject() 方法取消。这是操作在其中执行的类的实例化:

GenerateStats genStats = new GenerateStats();

这是我的 DoWork 函数,只要其他类中的事件被调用,它就会调用 ReportProgress 方法。它还从执行操作的其他类generateForSubject() 调用方法。

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

    genStats.ProgressChanged += (s, pe) => worker.ReportProgress(pe.ProgressPercentage, pe.UserState);
    genStats.generateForSubject();
}

这是应该启动取消并运行CancelAsync()的按钮单击事件处理程序

private void btnStop_Click(object sender, EventArgs e)
{
    if (backgroundWorker.IsBusy)
    {
        backgroundWorker.CancelAsync();
    }
}

这是我执行操作的单独类,以及创建 ProgressChanged 事件处理程序,因此我的类可以使用进度信息更新表单。如果取消功能可以类似地执行,那就太棒了。

public event ProgressChangedEventHandler ProgressChanged;

protected virtual void OnProgressChanged(int progress, string message)
{
    if (ProgressChanged != null)
    {
        ProgressChanged(this, new ProgressChangedEventArgs(progress, message));
    }
}

public void generateForSubject()
{
    //Perform db operation not important, but it takes time

    OnProgressChanged(33, "Finished 1st set of stats");
    //I hope to check for cancellation here

    //Perform db operation not important, but it takes time

    OnProgressChanged(66, "Finished 2nd set of stats");
    //I hope to check for cancellation here        

    //Perform db operation not important, but it takes time

    OnProgressChanged(99, "Finished 3rd set of stats");
    //I hope to check for cancellation here
}

只是为了澄清我的要求是否有任何不确定性,有什么方法可以让我支持在另一个类中取消我的 backgroundWorker 而无需将 backgroundWorker 传递给方法。如果绝对没有办法,我必须这样做,那么我将通过 backgroundWorker

【问题讨论】:

    标签: c# winforms backgroundworker cancellation


    【解决方案1】:

    您的方法应定期检查 CancellationPending 属性以查看是否发出取消请求。然后决定取消操作。请参阅MSDN link

    来自 MSDN:

    请注意,您在 DoWork 事件处理程序中的代码可能会完成 作为取消请求工作,并且您的轮询循环 可能会错过 CancellationPending 设置为 true。在这种情况下, System.ComponentModel.RunWorkerCompletedEventArgs 的取消标志 您的 RunWorkerCompleted 事件处理程序不会设置为 true,即使 尽管提出了取消请求。这种情况称为 竞争条件,是多线程编程中常见的问题。 有关多线程设计问题的更多信息,请参阅托管 线程最佳实践。

    编辑:

    如果您不希望将 backgroundworker 传递给 generateForSubject 方法。收到 CancelAsync 时在类中设置一个属性。并在每次操作之前从 generateForSubject 方法中检查该属性的值。

    【讨论】:

    • 该方法如何在不通过 backgroundWorker 的情况下知道有关 CancellationPending 的任何信息?
    • 就是这样。您需要在 generateForSubject 方法中使用它。并在每次大手术前进行检查。这是我所知道的。
    • 它不会工作,因为 OP 不想通过后台工作人员。
    【解决方案2】:

    如果您能更具体地说明您不愿意通过 BackgroundWorker 实例,那将会很有帮助。了解为什么这是设计要求有助于更好地回答您的问题。

    也就是说,您可以应用与 ProgressChanged 事件相同的理念并委托取消检查。例如:

    class GenerateStats
    {
        public event EventHandler<CancelEventArgs> CheckCancel;
    
        private bool OnCheckCancel()
        {
            EventHandler<CancelEventArgs> handler = CheckCancel;
    
            if (handler != null)
            {
                CancelEventArgs e = new CancelEventArgs();
    
                handler(this, e);
    
                return e.Cancel;
            }
    
            return false;
        }
    
        public void generateForSubject()
        {
            //Perform db operation not important, but it takes time
    
            OnProgressChanged(33, "Finished 1st set of stats");
            if (OnCheckCancel())
            {
                // Or other cancellation logic here
                return;
            }
    
            //Perform db operation not important, but it takes time
    
            OnProgressChanged(66, "Finished 2nd set of stats");
            if (OnCheckCancel())
            {
                // Or other cancellation logic here
                return;
            }
    
            //Perform db operation not important, but it takes time
    
            OnProgressChanged(99, "Finished 3rd set of stats");
            if (OnCheckCancel())
            {
                // Or other cancellation logic here
                return;
            }
        }
    }
    
    private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;
    
        genStats.ProgressChanged += (s, pe) => worker.ReportProgress(pe.ProgressPercentage, pe.UserState);
        genStats.CheckCancel += (sender1, e1) => e1.Cancel = worker.CancellationPending;
        genStats.generateForSubject();
    }
    

    这允许GenerateStats 类检查挂起的取消,而无需直接访问BackgroundWorker 实例,就像ProgressChanged 事件允许它通过BackgroundWorker 报告进度而不直接访问@987654328 @。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-01
      • 2023-03-23
      • 2018-03-18
      • 1970-01-01
      • 2012-03-27
      相关资源
      最近更新 更多