Share via


Parâmetros e valores de retorno for Multithreaded Procedures (C# e Visual Basic)

Fornecer e retornar valores em um aplicativo com vários segmentos é complicado porque o construtor para o segmento de classe deve ser uma referência a um procedimento que não leva argumentos e não retorna nenhum valor. As seções a seguir mostram algumas maneiras simples de fornecer parâmetros e retornar valores de procedimentos em segmentos separados.

Fornecer Parâmetros para os Procedimentos Multi-threaded

A melhor maneira de fornecer parâmetros para um chamada de método com vários segmentos é para quebrar o método de destino em uma classe e definir campos para a classe que servirá como parâmetros para o novo segmento. A vantagem dessa abordagem é que você pode criar uma nova instância da classe, com seus próprios parâmetros, toda vez que quiser iniciar um novo segmento. Por exemplo, suponha que você tenha uma função que calcula a área de um triângulo, como no código a seguir:

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

Você pode escrever uma classe que quebra a função CalcArea e cria campos para armazenar parâmetros de entrada, da seguinte maneira:

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

Para usar AreaClass, você pode criar um objeto AreaClass e definir as propriedades Base e Height conforme mostrado no código o seguir:

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

Observe que o procedimento TestArea não verifica o valor do campo Area após chamar o método CalcArea. Como CalcArea é executado em um segmento separado, não se pode garantir que o campo Area será definido se você marcá-lo imediatamente após chamar Thread.Start. A próxima seção discute uma melhor forma para retornar valores de procedimentos com vários segmentos.

Retornar Valores dos Procedimentos Multi-threaded

Retornar valores de procedimentos executados em segmentos separados é complicado pelo fato de que os procedimentos não podem ser funções e não é possível usar argumentos ByRef. A maneira mais fácil de retornar valores é usar o componente BackgroundWorker para gerenciar seus segmentos e disparar um evento quando a tarefa estiver concluída e processar os resultados com um manipulador de eventos.

O exemplo a seguir retorna um valor ao disparar um evento a partir de um procedimento em execução em um segmento separado:

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

Você pode fornecer parâmetros e retornar valores para segmentos de pool de segmentos, usando a variável de objeto de estado ByVal opcional do método QueueUserWorkItem. Segmentos timer de segmento também oferecem suporte a um objeto de estado para essa finalidade. Para obter informações sobre o pool de segmento e timers de segmento, consulte Thread Pooling (C# e Visual Basic) e (C# e Visual Basic) de Timers de segmento.

Consulte também

Tarefas

Demonstra Passo a passo: Multithreading com o componente BackgroundWorker (C# e Visual Basic)

Referência

Segmento de sincronização (C# e Visual Basic)

Eventos (Guia de programação do C#)

Representantes (guia de programação C#)

Conceitos

Thread Pooling (C# e Visual Basic)

Aplicativos multithread (C# e Visual Basic)

Outros recursos

Eventos (Visual Basic)

Delegados (Visual Basic)

Multithreading em componentes