天天看點

C# 多線程BackgroundWorker

在C#程式中,經常會有一些耗時較長的CPU密集型運算,如果直接在 UI 線程執行這樣的運算就會出現UI不響應的問題。解決這類問題的主要途徑是使用多線程,啟動一個背景線程,把運算操作放在這個背景線程中完成。但是原生接口的線程操作有一些難度,如果要更進一步的去完成線程間的通信就會難上加難。

用法概述

在窗體上建構一個BackgroundWorker 執行個體,在它的 DoWork事件處理函數中添加耗時的運算,然後調用它的RunWorkerAsync方法就可以了。

private BackgroundWorker _demoBGWorker = new BackgroundWorker();
_demoBGWorker.DoWork += BGWorker_DoWork;
_demoBGWorker.RunWorkerAsync();
private void BGWorker_DoWork(object sender, DoWorkEventArgs e)
{
  //在這裡執行耗時的運算。
  int sum = 0;
  for (int i = 0; i <= 100; i++)
  {
    sum += i;
  }
}
           

是不是有點太簡單了?那麼讓我們考慮下面的問題:

如果我們想要把參數傳遞給運算過程該怎麼做?

在運算過程中我們希望把實時的資訊顯示在UI上該怎麼辦?

如果我們想要取消正在進行的運算該怎麼辦?

如果運算過程出現異常我們又該如何處理?

接下來我們就一個一個的處理這些問題。

把參數傳遞給運算過程

直接把100寫死到運算過程中可不好,我們還打算允許使用者指定求和的範圍呢!是以需要把100作為參數傳遞給計算過程。在概述中我們通過調用RunWorkerAsync方法啟動計算過程,其實這個方法可以接受一個 object 類型的參數。通過它我們就可以把任何資料傳遞給計算過程:

//别忘了設定滾動條。
this.progressBarSum.Maximum = 100;
_demoBGWorker.RunWorkerAsync(100);
//下面是更新後的 BGWorker_DoWork 方法:
private void BGWorker_DoWork(object sender, DoWorkEventArgs e)
{
  //在這裡執行耗時的運算。
  int endNumber = 0;
  if(e.Argument != null)
  {
    endNumber = (int)e.Argument;
  }
  int sum = 0;
  for (int i = 0; i <= endNumber; i++)
  {
    sum += i;
  }
}
           

BGWorker_DoWork事件處理函數通過參數 e 的Argument屬性傳來了我們期望的運算資訊。

c#