Parametry i wartości zwracane dla procedur wielowątkowości (C# i Visual Basic)

Dostarczanie i zwracanie wartości w wielowątkowych aplikacji jest skomplikowane, ponieważ konstruktora dla klasy wątek musi być przekazany odniesienie do procedury, która nie przyjmuje żadnych argumentów i zwraca wartość nie.W poniższych sekcjach przedstawiono kilka prostych sposobów dostaw parametrów i procedur otrzymywania wartości w osobnych wątkach.

Dostarczanie parametry procedury wielowątkowe

Najlepszym sposobem dostaw parametry wywołania metody wielowątkowe jest otaczanie metody docelowej w klasie i definiowania pól dla tej klasy, który będzie służyć jako parametry dla nowego wątku.Zaletą tego podejścia jest to, że można utworzyć nową instancję klasy, z własnej parametry za każdym razem, gdy chcesz rozpocząć nowy wątek.Załóżmy na przykład, funkcji, która oblicza powierzchnię trójkąta, jak w poniższym kodzie:

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;
}

Można napisać klasa, która otacza CalcArea funkcję i tworzy pola do przechowywania parametrów wejściowych w następujący sposób:

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());
    }
}

Aby użyć AreaClass, można utworzyć AreaClass obiekt, a następnie ustaw Base i Height właściwości, jak pokazano w poniższym kodzie:

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();
}

Warto zauważyć, że TestArea procedury nie sprawdza wartość Area pola po wywołaniu CalcArea metody.Ponieważ CalcArea jest uruchamiany w osobnym wątku, Area pole nie jest gwarantowane, aby ustawić, jeśli użytkownik sprawdza natychmiast po wywołaniu Thread.Start.Następnej sekcji omówiono lepszy sposób do zwracania wartości z procedur wielowątkowe.

Zwracanie wartości z procedur wielowątkowe

Zwracanie wartości z procedur, które są uruchamiane w osobnych wątkach jest skomplikowana przez fakt, że procedury nie może być funkcji i nie można używać ByRef argumentów.Najprostszym sposobem zwracają wartości jest użycie BackgroundWorker składnika do zarządzania swoje wątki i podnieść zdarzenie, kiedy zadanie jest wykonywane i przetworzenia wyników z obsługą zdarzeń.

Poniższy przykład zwraca wartość poprzez podnoszenie zdarzenia z procedury uruchomione w osobnym wątku:

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());
}

Można podać parametry i zwracają wartości do wątku puli wątków, przy użyciu opcjonalnej ByVal obiekt stanu zmiennej QueueUserWorkItem metody.Wątki wątku czasomierza obsługują także obiekt stanu dla tego celu.Informacje dotyczące puli wątków i czasomierzy wątku, zobacz Pula wątków (C# i Visual Basic) i Czasomierze wątków (C# i Visual Basic).

Zobacz też

Zadania

Wskazówki: wielowątkowość ze składnikiem BackgroundWorker (C# and Visual Basic)

Informacje

Synchronizacja wątku (C# i Visual Basic)

Zdarzenia (Przewodnik programowania w języku C#)

Delegaty (Przewodnik programowania w języku C#)

Koncepcje

Pula wątków (C# i Visual Basic)

Aplikacje wielowątkowe (C# i Visual Basic)

Inne zasoby

Zdarzenia (Visual Basic)

Delegaty (Visual Basic)

Wielowątkowość w składnikach