2009-09-24 63 views
1
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(); 
      } 
     } 
    } 
} 

我发现,执行以下代码后:C#BackgroundWorker的线程问题

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

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

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

任何人都可以在这方面帮助我吗?

+0

实际上,这是一个数据库应用程序的模拟,其中MyClass.LogOperation() - 模拟长时间的获取操作。 – anonymous 2009-09-24 13:17:53

+0

+1我还想要一个解决方案来取消长时间运行的异步操作(即数据库调用)。我会看... :) – Pwninstein 2009-09-24 13:40:00

回答

4

的解决办法是改变你的BackgroundThreadDoWork()事件处理更加敏感:它需要打破其工作分成更小的块和轮询工人的CancellationPending频繁,足以满足您的应用程序的需要。


编辑:给您添加的代码,你将无法做你想要用BackgroudWorker喜欢什么。

如果您不能修改MyClass.LongOperation(和它不提供任何挂钩,让你中断它),但你想要让用户取消该操作完成之前,你可以通过创建自己的Thread(作为后台实现这个线程,如果放弃它,它不会让你的应用程序保持打开状态)。从理论上讲,你也可以做到这一点使用ThreadPool.QueueUserWorkItem,但它是一个坏主意,使用ThreadPool长期运行的流程(见The Managed Thread Pool了解详细信息)。

最后,你可以考虑将长期运行的操作带外 - 写一个消息队列,调用服务,或使用一些其他技术来将它交给另一个进程。

+0

+1。党,1分钟内完成4个相同的答案。我刚刚删除了我的。 – 2009-09-24 13:13:25

+0

这是不可能的,如果我需要保持我的较低逻辑层不变。任何其他方式? – anonymous 2009-09-24 13:13:44

+0

@JMSA - 我不知道。 SO上有几个类似的问题(例如,http://stackoverflow.com/questions/543811/kill-the-thread-of-backgroundworker)。结果是,如果您打算放弃线程,则必须使用与BackgroundWorker不同的机制。 – 2009-09-24 13:22:37

1

这取决于你DoWork()方法是如何经常检查CancellationPending属性。

这是取消的请求,你是不是杀线程。参考MSDN页面上CancelAsync

有要强行终止BackgroundWorker的,使用一个线程,而不是没有真正的方法。

1

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

在你的话,你的Git一个不错的isssue。要解决这个

一种方式是建立一个特定的子类的多线程,离开不可避免讨厌位出逻辑的。

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

这样你就可以停止比longoperation年底更加随心所欲。

多线程无功能的方式总是会影响你的代码,再坚持的时候,你将需要锁;-)

0

你能描述一下这个问题是什么?当然最好让后台工作线程完成(就像它的设计一样)。

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