C#BackgroundWorker线程问题

时间:2009-09-24 13:04:02

标签: c# backgroundworker

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace ClassLibrary
{
    public class MyClass
    {
        public static string LongOperation()
        {
            Thread.Sleep(new TimeSpan(0,0,30));

            return "HelloWorld";
        }
    }
}

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using ClassLibrary;

namespace BackgroungWorker__HelloWorld
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

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

            MyClass.LongOperation();

            e.Result = "[Result]";
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {            
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            try
            {
                if (e.Cancelled)
                {
                    MessageBox.Show("The task has been cancelled");
                }
                else if (e.Error != null)
                {
                    MessageBox.Show("Error. Details: " + (e.Error as Exception).ToString());
                }
                else
                {
                    MessageBox.Show("The task has been completed. Results: " + e.Result!=null?e.Result.ToString():" null");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            backgroundWorker1.RunWorkerAsync();
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            if (backgroundWorker1.IsBusy)
            {
                backgroundWorker1.CancelAsync();
            }
            else
            {
                this.Close();
            }
        }
    }
}

我在执行以下代码后发现:

private void btnClose_Click(object sender, EventArgs e)
        {
            if (backgroundWorker1.IsBusy)
            {
                backgroundWorker1.CancelAsync();
            }
            else
            {
                this.Close();//"this" means the Form object
            }
        }

backgroundWorker1的线程不会立即被杀死。这需要一些时间。

这是构建我的应用程序逻辑时的一个问题。

在这方面,有人可以帮助我吗?

4 个答案:

答案 0 :(得分:4)

解决方案是更改BackgroundThread的{​​{1}}事件处理程序以提高响应速度:它需要将其工作分解为更小的块并且频繁地轮询工作者DoWork()以满足您的应用程序的需求。


修改:根据您添加的代码,您将无法使用CancellationPending执行您想要的操作。

如果你不能修改BackgroudWorker(并且它没有提供任何钩子让你打断它)但你想让用户在该操作完成之前取消,你可以通过创建自己的{{{ 1}}(作为后台线程,如果你放弃它,它将不会保持你的应用程序打开)。从理论上讲,您也可以使用MyClass.LongOperation来执行此操作,但对于长时间运行的进程使用Thread是个坏主意(有关详细信息,请参阅The Managed Thread Pool)。

最后,您可以考虑将长时间运行的操作移出带外 - 将消息写入队列,调用服务或使用其他技术将其移交给另一个进程。

答案 1 :(得分:1)

这取决于DoWork()方法检查CancellationPending属性的频率。

这是取消请求,你不是要杀死线程。请参阅CancelAsync

上的msdn页面

没有真正的方法强制终止BackgroundWorker,而是使用线程。

答案 2 :(得分:1)

由workerthreads代码检查CancellationPending属性。 将始终执行在这些检查之间执行的代码,从而导致延迟。

在你的评论中,你会发现一个很好的问题。

解决这个问题的一种方法是为多线程构建一个特定的子类,将不可避免的令人讨厌的位置留在逻辑之外。

主类应该为LongOperation提供一个调用其他方法的模板方法,然后线程子类可以覆盖longoperation中调用的方法,并且在让mainclass方法执行实际工作之前执行CancellationPending属性的检查。 / p>

这样你就可以比在长期操作结束时更加随意。

以非功能方式进行多线程处理将始终影响您的代码,在您需要锁定时保持不变; - )

答案 3 :(得分:0)

你能说明问题是什么吗?当然最好让后台工作线程优雅地完成(就像设计一样)。

您知道可以通过执行backgroundWorker1来定期检查取消。CancellationPending