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 Timers (C# e Visual Basic) de segmento.

Consulte também

Tarefas

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

Referência

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

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

Representantes (guia de programação do 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