2009-09-24 141 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