Compartir a través de


Parámetros y valores devueltos para procedimientos multiproceso (C# y Visual Basic)

Suministrar y devolver valores en aplicaciones multiproceso es complicado, porque se debe pasar una referencia a un procedimiento que no tome ningún argumento ni devuelva ningún valor al constructor de la clase de subproceso. Las secciones siguientes muestran formas sencillas de suministrar parámetros y devolver valores de procedimientos en subprocesos separados.

Suministrar parámetros para procedimientos multiproceso

La mejor forma de suministrar parámetros para una llamada a un método multiproceso es ajustar el método de destino en una clase y definir campos para dicha clase que servirán como parámetros para el nuevo subproceso. La ventaja de este planteamiento es que se puede crear una nueva instancia de la clase, con sus propios parámetros, cada vez que se desee iniciar un nuevo subproceso. Por ejemplo, suponga que tiene una función que calcula el área de un triángulo, como en el código siguiente:

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

Se puede escribir una clase que encapsule la función CalcArea y cree campos para almacenar parámetros de entrada de la forma indicada a continuación:

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 utilizar AreaClass, puede crear un objeto AreaClass y establecer las propiedades Base y Height como se muestra en el código siguiente:

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

Tenga en cuenta que el procedimiento TestArea no comprueba el valor del campo Area después de llamar al método the CalcArea. Como the CalcArea se ejecuta en un subproceso independiente, no se garantiza que se establezca el valor del campo Area si se comprueba inmediatamente después de llamar a Thread.Start. La sección siguiente explica una mejor forma de devolver valores de procedimientos multiproceso.

Devolver valores de procedimientos multiproceso

Devolver valores de procedimientos multiproceso que se ejecutan en subprocesos separados es complicado por el hecho de que los procedimientos no pueden ser funciones y no pueden utilizar argumentos ByRef. La forma más sencilla de devolver valores consiste en utilizar el componente BackgroundWorker para administrar los subprocesos, generar un evento cuando finalice la tarea y procesar los resultados con un controlador de eventos.

El ejemplo siguiente devuelve un valor mediante la generación de un evento desde un procedimiento que se ejecuta en un subproceso 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());
}

Se pueden proporcionar parámetros y valores devueltos a subprocesos de grupos de subprocesos, mediante la variable opcional de objeto de estado ByVal del método QueueUserWorkItem. Los subprocesos de temporizador de subproceso admiten también un objeto de estado con este propósito. Para obtener información sobre la agrupación de subprocesos y los temporizadores de subprocesos, vea Agrupación de subprocesos (Visual C# y Visual Basic) y Temporizadores de subprocesos (Visual C# y Visual Basic).

Vea también

Tareas

Tutorial: Multithreading con el componente BackgroundWorker (C# y Visual Basic)

Referencia

Sincronización de subprocesos (C# y Visual Basic)

Eventos (Guía de programación de C#)

Delegados (Guía de programación de C#)

Conceptos

Agrupación de subprocesos (Visual C# y Visual Basic)

Aplicaciones multiproceso (C# y Visual Basic)

Otros recursos

Eventos (Visual Basic)

Delegados (Visual Basic)

Subprocesamiento múltiple en componentes