多執行緒程序的參數和傳回值
更新:2007 年 11 月
因為必須將執行緒類別的建構函式 (Constructor) 傳遞給不使用引數且不傳回值的程序參考,所以在多執行緒應用程式 (Multithreaded Application) 中提供和傳回值並不容易。以下章節將說明一些簡單的方法,來提供參數以及從個別執行緒上的程序傳回值。
提供多執行緒程式的參數
為多執行緒方法呼叫提供參數的最佳做法是,將目標方法包裝在類別之中,接著為此類別定義將當做新執行緒參數的欄位。這種做法的好處是,每次您想要啟動新執行緒時,就可以建立類別的新執行個體以及其本身的參數。例如,假設您有個函式是用來計算三角形的面積,如下列程式碼所示:
Function CalcArea(ByVal Base As Double, ByVal Height As Double) As Double
CalcArea = 0.5 * Base * Height
End Function
您可以寫入類別來包裝 CalcArea 函式,並建立欄位以儲存輸入參數,如以下所示:
Class AreaClass
Public Base As Double
Public Height As Double
Public Area As Double
Sub CalcArea()
Area = 0.5 * Base * Height
MsgBox("The area is: " & Area)
End Sub
End Class
若要使用 AreaClass,您可以建立 AreaClass 物件,並設定 Base 和 Height 屬性,如下列程式碼所示:
Protected Sub TestArea()
Dim AreaObject As New AreaClass
Dim Thread As New System.Threading.Thread _
(AddressOf AreaObject.CalcArea)
AreaObject.Base = 30
AreaObject.Height = 40
Thread.Start()
End Sub
請注意,TestArea 程序在呼叫 CalcArea 方法之後,不會檢查 Area 欄位的值。由於 CalcArea 是在個別的執行緒上執行,因此如果您在呼叫 Thread.Start 之後立即檢查 Area 欄位,則不保證它已設定好。下一章節將討論從多執行緒程序傳回值的較佳做法。
從多執行緒程序傳回值
從個別執行緒上執行的程序傳回值之所以複雜的原因是,程序不能是函式且無法使用 ByRef 引數。傳回值的最簡單方式是使用 BackgroundWorker 元件管理執行緒,並在工作完成時引發事件,且使用事件處理常式處理結果。
以下範例將藉由引發事件來從個別執行緒上執行的程序傳回值:
Private Class AreaClass2
Public Base As Double
Public Height As Double
Function CalcArea() As Double
' Calculate the area of a triangle.
Return 0.5 * Base * Height
End Function
End Class
Private WithEvents BackgroundWorker1 As New System.ComponentModel.BackgroundWorker
Private Sub TestArea2()
Dim AreaObject2 As New AreaClass2
AreaObject2.Base = 30
AreaObject2.Height = 40
' Start the asynchronous operation.
BackgroundWorker1.RunWorkerAsync(AreaObject2)
End Sub
' This method runs on the background thread when it starts.
Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, _
ByVal e As System.ComponentModel.DoWorkEventArgs) _
Handles BackgroundWorker1.DoWork
Dim AreaObject2 As AreaClass2 = CType(e.Argument, AreaClass2)
' Return the value through the Result property.
e.Result = AreaObject2.CalcArea()
End Sub
' This method runs on the main thread when the background thread finishes.
Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, _
ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) _
Handles BackgroundWorker1.RunWorkerCompleted
' Access the result through the Result property.
Dim Area As Double = CDbl(e.Result)
MsgBox("The area is: " & Area)
End Sub
使用 QueueUserWorkItem 方法的選擇性 ByVal 狀態物件變數,即可提供參數並將值傳至執行緒集區執行緒。執行緒計時器執行緒也支援狀態物件,以達成這個目的。如需執行緒集區和執行緒計時器的詳細資訊,請參閱執行緒共用和執行緒計時器。