可以編寫能同時執行多個任務的應用程序。此能力(稱為“多線程處理”或“自由線程處理”)是設計處理器密集型且要求用戶輸入的組件的強大方法。計算工資表信息的組件就是一個可能利用多線程處理的組件示例。該組件可以在一個線程上處理用戶輸入到數據庫的數據,而在另一個線程上執行頻繁使用處理器的工資表計算。通過在不同的線程上運行這些進程,用戶不必等到計算機完成計算,就可以輸入其他數據。在本演練中,將創建一個簡單的多線程組件,該組件可以同時執行若干個復雜計算。
創建項目
應用程序將包括單個窗體和一個組件。用戶將輸入值並指示該組件開始計算。然後,窗體將接收來自該組件的值,將其顯示在標簽控件中。該組件將執行頻繁使用處理器的計算,並在完成後通知窗體。您將在組件中創建公共變量,用以保存從用戶界面收到的值。同時,您還將在組件中實現一些方法,根據這些變量的值執行計算。
注意 盡管對於計算值的方法來說,函數通常更為可取,但不能在線程之間傳遞參數,也不能返回值。有很多向線程提供值和從線程接收值的簡單方法。在本演示中,將通過更新公共變量將值返回到用戶界面,當線程執行完畢後,使用事件來通知主程序。
創建窗體
創建新的“Windows 應用程序”項目。
將應用程序命名為 Calculations,並將 Form1.cs 重命名為 frmCalculations.cs。
該窗體將用作應用程序的主用戶界面。
雙擊設計器上的窗體以打開代碼編輯器。在“編輯”菜單中,選擇“查找和替換”,然後選擇“替換”。使用“全部替換”將 Form1 替換為 frmCalculations。
在“解決方案資源管理器”中,右擊“frmCalculations.cs”並選擇“視圖設計器”。設計器打開。
向窗體中添加 5 個 Label 控件、4 個 Button 控件和 1 個 TextBox 控件。
為這些控件設置屬性,如下所示:
控件
名稱
文本
Label1
lblFactorial1
(空白)
Label2
lblFactorial2
(空白)
Label3
lblAddTwo
(空白)
Label4
lblRunLoops
(空白)
Label5
lblTotalCalculations
(空白)
Button1
btnFactorial1
Factorial
Button2
btnFactorial2
Factorial - 1
Button3
btnAddTwo
Add Two
Button4
btnRunLoops
Run a Loop
Textbox1
txtValue
(空白)
創建 Calculator 組件
從“項目”菜單中選擇“添加組件”。
將組件命名為 Calculator。
向 Calculator 組件添加公共變量
為 Calculator 打開代碼編輯器。
添加創建公共變量的語句,這些變量用於將值從 frmCalculations 傳遞給每個線程。
變量 varTotalCalculations 將保留該組件執行的計算總數的累計值,而其他變量將接收來自窗體的值。
public int varAddTwo;
public int varFact1;
public int varFact2;
public int varLoopValue;
public double varTotalCalculations = 0;
向 Calculator 組件添加方法和事件
為事件聲明委托,組件將使用這些事件向窗體傳遞值。
注意 盡管您將聲明 4 個事件,但由於其中的兩個事件將具有相同的簽名,因此只需要創建 3 個委托。
緊接著上一步輸入的變量聲明的下方,鍵入下列代碼:
// This delegate will be invoked with two of your events.
public delegate void FactorialCompleteHandler(double Factorial, double TotalCalculations);
public delegate void AddTwoCompleteHandler(int Result, double TotalCalculations);
public delegate void LoopCompleteHandler(double TotalCalculations, int Counter);
聲明組件將用來與應用程序進行通信的事件。為實現此目的,緊接著上一步輸入的代碼的下方,添加下列代碼。
public event FactorialCompleteHandler FactorialComplete;
public event FactorialCompleteHandler FactorialMinusOneComplete;
public event AddTwoCompleteHandler AddTwoComplete;
public event LoopCompleteHandler LoopComplete;
緊接著上一步鍵入的代碼的下方,鍵入下列代碼:
// This method will calculate the value of a number minus 1 factorial
// (varFact2-1!).
public void FactorialMinusOne()
{
double varTotalAsOfNow = 0;
double varResult = 1;
// Performs a factorial calculation on varFact2 - 1.
for (int varX = 1; varX <= varFact2 - 1; varX++)
{
varResult *= varX;
// Increments varTotalCalculations and keeps track of the current
// total as of this instant.
varTotalCalculations += 1;
varTotalAsOfNow = varTotalCalculations;
}
// Signals that the method has completed, and communicates the
// result and a value of total calculations performed up to this
// point.
FactorialMinusOneComplete(varResult, varTotalAsOfNow);
}
// This method will calculate the value of a number factorial.
// (varFact1!)
public void Factorial()
{
double varResult = 1;
double varTotalAsOfNow = 0;
for (int varX = 1; varX <= varFact1; varX++)
{
varResult *= varX;
varTotalCalculations += 1;
varTotalAsOfNow = varTotalCalculations;
}
FactorialComplete(varResult, varTotalAsOfNow);
}
// This method will add two to a number (varAddTwo+2).
public void AddTwo()
{
double varTotalAsOfNow = 0;
int varResult = varAddTwo + 2;
varTotalCalculations += 1;
varTotalAsOfNow = varTotalCalculations;
AddTwoComplete(varResult, varTotalAsOfNow);
}
// This method will run a loop with a nested loop varLoopValue times.
public void RunALoop()
{
int varX;
double varTotalAsOfNow = 0;
for (varX = 1; varX <= varLoopValue; varX++)
{
// This nested loop is added solely for the purpose of slowing down
// the program and creating a processor-intensive application.
for (int varY = 1; varY <= 500; varY++)
{
varTotalCalculations += 1;
varTotalAsOfNow = varTotalCalculations;
}
}
LoopComplete(varTotalAsOfNow, varLoopValue);
}
將用戶輸入傳輸到組件
下一步是向 frmCalculations 添加代碼,以接收用戶輸入,以及從 Calculator 組件接收值和向它傳輸值。
實現 frmCalculations 的前端功能
在代碼編輯器中打開 frmCalculations。
找到 public class frmCalculations 語句。緊接著 { 的下方鍵入:
Calculator Calculator1;
找到構造函數。緊接著 } 之前,添加以下行:
// Creates a new instance of Calculator.
Calculator1 = new Calculator();
在設計器中單擊每個按鈕,為每個控件的單擊事件處理程序生成代碼大綱,並添加代碼以創建這些處理程序。
完成後,單擊事件處理程序應該類似於以下形式:
private void btnFactorial1_Click(object sender, System.EventArgs e)
// Passes the value typed in the txtValue to Calculator.varFact1.
{
Calculator1.varFact1 = int.Parse(txtValue.Text);
// Disables the btnFactorial1 until this calculation is complete.
btnFactorial1.Enabled = false;
Calculator1.Factorial();
}
private void btnFactorial2_Click(object sender, System.EventArgs e)
{
Calculator1.varFact2 = int.Parse(txtValue.Text);
btnFactorial2.Enabled = false;
Calculator1.FactorialMinusOne();
}
private void btnAddTwo_C