共用方式為


多執行緒程序的參數和傳回值 (C# 和 Visual Basic)

因為必須將執行緒類別的建構函式 (Constructor) 傳遞給不使用引數且不傳回值的程序參考,所以在多執行緒應用程式 (Multithreaded Application) 中提供和傳回值並不容易。 以下章節將說明一些簡單的方法,來提供參數以及從個別執行緒上的程序傳回值。

提供多執行緒程式的參數

為多執行緒方法呼叫提供參數的最佳做法是,將目標方法包裝在類別之中,接著為此類別定義將當做新執行緒參數的欄位。 這種做法的好處是,每次您想要啟動新執行緒時,就可以建立類別的新執行個體以及其本身的參數。 例如,假設您有個函式是用來計算三角形的面積,如下列程式碼所示:

Function CalcArea(ByVal Base As Double, ByVal Height As Double) As Double
    CalcArea = 0.5 * Base * Height
End Function
double CalcArea(double Base, double Height)
{
    return 0.5 * Base * Height;
}

您可以寫入類別來包裝 CalcArea 函式,並建立欄位以儲存輸入參數,如以下所示:

Class AreaClass
    Public Base As Double
    Public Height As Double
    Public Area As Double
    Sub CalcArea()
        Area = 0.5 * Base * Height
        MessageBox.Show("The area is: " & Area.ToString)
    End Sub
End Class
class AreaClass
{
    public double Base;
    public double Height;
    public double Area;
    public void CalcArea()
    {
        Area = 0.5 * Base * Height;
        MessageBox.Show("The area is: " + Area.ToString());
    }
}

若要使用 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
protected void TestArea()
{
    AreaClass AreaObject = new AreaClass();

    System.Threading.Thread Thread =
        new System.Threading.Thread(AreaObject.CalcArea);
    AreaObject.Base = 30;
    AreaObject.Height = 40;
    Thread.Start();
}

請注意,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)
    MessageBox.Show("The area is: " & Area.ToString)
End Sub
class AreaClass2
{
    public double Base;
    public double Height;
    public double CalcArea()
    {
        // Calculate the area of a triangle.
        return 0.5 * Base * Height;
    }
}

private System.ComponentModel.BackgroundWorker BackgroundWorker1
    = new System.ComponentModel.BackgroundWorker();

private void TestArea2()
{
    InitializeBackgroundWorker();

    AreaClass2 AreaObject2 = new AreaClass2();
    AreaObject2.Base = 30;
    AreaObject2.Height = 40;

    // Start the asynchronous operation.
    BackgroundWorker1.RunWorkerAsync(AreaObject2);
}

private void InitializeBackgroundWorker()
{
    // Attach event handlers to the BackgroundWorker object.
    BackgroundWorker1.DoWork +=
        new System.ComponentModel.DoWorkEventHandler(BackgroundWorker1_DoWork);
    BackgroundWorker1.RunWorkerCompleted +=
        new System.ComponentModel.RunWorkerCompletedEventHandler(BackgroundWorker1_RunWorkerCompleted);
}

private void BackgroundWorker1_DoWork(
    object sender,
    System.ComponentModel.DoWorkEventArgs e)
{
    AreaClass2 AreaObject2 = (AreaClass2)e.Argument;
    // Return the value through the Result property.
    e.Result = AreaObject2.CalcArea();
}

private void BackgroundWorker1_RunWorkerCompleted(
    object sender,
    System.ComponentModel.RunWorkerCompletedEventArgs e)
{
    // Access the result through the Result property.
    double Area = (double)e.Result;
    MessageBox.Show("The area is: " + Area.ToString());
}

使用 QueueUserWorkItem 方法的選擇性 ByVal 狀態物件變數,即可提供參數並將值傳至執行緒集區執行緒。 執行緒計時器執行緒也支援狀態物件,以達成這個目的。 如需執行緒集區和執行緒計時器的詳細資訊,請參閱執行緒集區 (C# 和 Visual Basic)執行緒計時器 (C# 和 Visual Basic)

請參閱

工作

逐步解說:使用 BackgroundWorker 元件進行多執行緒處理 (C# 和 Visual Basic)

參考

執行緒同步處理 (C# 和 Visual Basic)

事件 (C# 程式設計手冊)

委派 (C# 程式設計手冊)

概念

執行緒集區 (C# 和 Visual Basic)

多執行緒應用程式 (C# 和 Visual Basic)

其他資源

事件 (Visual Basic)

委派 (Visual Basic)

元件中的多執行緒