Share via


Tutorial: Crear un componente sencillo con múltiples procesos en Visual Basic

Actualización: noviembre 2007

Aunque el componente BackgroundWorker viene a reemplazar y a agregar funcionalidad al espacio de nombres System.Threading, éste se conserva a efectos de compatibilidad con versiones anteriores y uso futuro, según sea el caso. Para obtener más información, vea Información general sobre el componente BackgroundWorker.

Se pueden escribir aplicaciones que sean capaces de realizar varias tareas simultáneamente. Esta capacidad, denominada subprocesamiento múltiple o subprocesamiento libre, es un modo eficaz de diseñar componentes que hagan un uso intensivo del procesador y requieran acción del usuario. Un ejemplo claro de un componente que podría hacer uso del subprocesamiento múltiple sería un componente que calculara información de nóminas. Este componente podría procesar los datos que un usuario incluyó en una base de datos en un subproceso mientras, en otro, se llevan a cabo cálculos de nómina con un uso intensivo del procesador. Al ejecutar estos procesos en subprocesos separados, los usuarios no tienen que esperar a que el equipo finalice los cálculos antes de especificar datos adicionales. En este tutorial, se creará un componente multiproceso simple que realiza varios cálculos complejos de forma simultánea.

Crear el proyecto

La aplicación constará de un único formulario y un componente. El usuario especificará los valores e indicará al componente que puede comenzar los cálculos. El formulario recibirá entonces los valores del componente y los mostrará en controles Label. El componente realizará los cálculos con un uso intensivo del procesador y le hará una señal al formulario cuando haya terminado. Se crearán variables públicas en el componente para albergar los valores recibidos de la interfaz de usuario. Además, se implementarán métodos en el componente para realizar los cálculos según los valores de estas variables.

Nota:

Aunque suele ser preferible una función para un método que calcule un valor, no se pueden pasar argumentos ni devolver valores entre subprocesos. Existen muchos modos simples de suministrar valores a los subprocesos y de recibir valores de ellos. En esta demostración, se devolverán valores a la interfaz de usuario mediante la actualización de las variables públicas, y se usarán eventos para notificar al programa principal cuándo ha finalizado su ejecución un subproceso.

Los cuadros de diálogo y comandos de menú que se ven pueden diferir de los descritos en la Ayuda, en función de la configuración activa o la edición. Para cambiar la configuración, elija la opción Importar y exportar configuraciones en el menú Herramientas. Para obtener más información, vea Valores de configuración de Visual Studio.

Para crear el formulario

  1. Cree un proyecto nuevo de Aplicación para Windows.

  2. Asigne un nombre a la aplicación Calculations y cambie el nombre Form1.vb a frmCalculations.vb.

  3. Cuando Visual Studio le pida que cambie el nombre del elemento de código Form1, haga clic en Sí.

    Este formulario servirá como interfaz de usuario principal de la aplicación.

  4. Agregue al formulario cinco controles Label, cuatro controles Button y un control TextBox.

    Control

    Nombre

    Texto

    Label1

    lblFactorial1

    (En blanco)

    Label2

    lblFactorial2

    (En blanco)

    Label3

    lblAddTwo

    (En blanco)

    Label4

    lblRunLoops

    (En blanco)

    Label5

    lblTotalCalculations

    (En blanco)

    Button1

    btnFactorial1

    Factorial

    Button2

    btnFactorial2

    Factorial - 1

    Button3

    btnAddTwo

    Agregar dos

    Button4

    btnRunLoops

    Ejecutar un bucle

    TextBox1

    txtValue

    (En blanco)

Para crear el componente Calculator

  1. En el menú Proyecto, elija Agregar componente.

  2. Asigne a este componente el nombre Calculator.

Para agregar variables públicas al componente Calculator

  1. Abra Calculator en el Editor de código.

  2. Agregue instrucciones para crear las variables públicas que usará para pasar los valores de frmCalculations a cada subproceso.

    La variable varTotalCalculations mantendrá un total actualizado del número de cálculos realizados por el componente, y las demás variables recibirán sus valores del formulario.

    Public varAddTwo As Integer
    Public varFact1 As Integer
    Public varFact2 As Integer
    Public varLoopValue As Integer
    Public varTotalCalculations As Double = 0
    

Para agregar métodos y eventos al componente Calculator

  1. Declare los eventos que usará el componente para comunicar valores al formulario. Inmediatamente debajo de las declaraciones de las variables realizadas en el paso anterior, escriba el código siguiente:

    Public Event FactorialComplete(ByVal Factorial As Double, ByVal _
       TotalCalculations As Double)
    Public Event FactorialMinusComplete(ByVal Factorial As Double, ByVal _
       TotalCalculations As Double)
    Public Event AddTwoComplete(ByVal Result As Integer, ByVal _
       TotalCalculations As Double)
    Public Event LoopComplete(ByVal TotalCalculations As Double, ByVal _
       Counter As Integer)
    
  2. Inmediatamente debajo de las declaraciones de las variables realizadas en el paso 1, escriba el código siguiente:

    ' This sub will calculate the value of a number minus 1 factorial 
    ' (varFact2-1!).
    Public Sub FactorialMinusOne()
       Dim varX As Integer = 1
       Dim varTotalAsOfNow As Double
       Dim varResult As Double = 1
       ' Performs a factorial calculation on varFact2 - 1.
       For varX = 1 to varFact2 - 1
          varResult *= varX
          ' Increments varTotalCalculations and keeps track of the current
          ' total as of this instant.
          varTotalCalculations += 1
          varTotalAsOfNow = varTotalCalculations
       Next varX
       ' Signals that the method has completed, and communicates the 
       ' result and a value of total calculations performed up to this 
       ' point
       RaiseEvent FactorialMinusComplete(varResult, varTotalAsOfNow)
    End Sub
    
    ' This sub will calculate the value of a number factorial (varFact1!).
    Public Sub Factorial()
       Dim varX As Integer = 1
       Dim varResult As Double = 1
       Dim varTotalAsOfNow As Double = 0
       For varX = 1 to varFact1
           varResult *= varX
           varTotalCalculations += 1
           varTotalAsOfNow = varTotalCalculations
       Next varX
       RaiseEvent FactorialComplete(varResult, varTotalAsOfNow)
    End Sub
    
    ' This sub will add two to a number (varAddTwo + 2).
    Public Sub AddTwo()
       Dim varResult As Integer
       Dim varTotalAsOfNow As Double
       varResult = varAddTwo + 2
       varTotalCalculations += 1
       varTotalAsOfNow = varTotalCalculations
       RaiseEvent AddTwoComplete(varResult, varTotalAsOfNow)
    End Sub
    
    ' This method will run a loop with a nested loop varLoopValue times.
    Public Sub RunALoop()
       Dim varX As Integer
       Dim varY As Integer
       Dim varTotalAsOfNow As Double
       For varX = 1 To varLoopValue
          ' This nested loop is added solely for the purpose of slowing
          ' down the program and creating a processor-intensive
          ' application.
          For varY = 1 To 500
             varTotalCalculations += 1
             varTotalAsOfNow = varTotalCalculations
          Next
       Next
       RaiseEvent LoopComplete(varTotalAsOfNow, varX - 1)
    End Sub
    

Transferir datos proporcionados por el usuario al componente

El paso siguiente consiste en agregar código a frmCalculations para recibir datos proporcionados por el usuario y para transferir y recibir valores a y desde el componente Calculator.

Para implementar la funcionalidad de interfaz cliente en frmCalculations

  1. En el menú Generar, seleccione Generar solución .

  2. Abra frmCalculations en el Diseñador de Windows Forms.

  3. En el Cuadro de herramientas, busque la ficha Componentes para cálculos. Arrastre el componente Calculator a la superficie de diseño.

  4. En la ventana Propiedades, haga clic en el botón Eventos.

  5. Haga doble clic en cada uno de los cuatro eventos para crear controladores de eventos en frmCalculations. Tendrá que volver al diseñador después de crear cada controlador de eventos.

  6. Agregue el código siguiente para controlar los eventos que el formulario recibirá de Calculator1:

    Private Sub Calculator1_AddTwoComplete(ByVal Result As System.Int32, ByVal TotalCalculations As System.Double) Handles Calculator1.AddTwoComplete
        lblAddTwo.Text = Result.ToString
        btnAddTwo.Enabled = True
        lblTotalCalculations.Text = "TotalCalculations are " & _
            TotalCalculations.ToString
    End Sub
    
    Private Sub Calculator1_FactorialComplete(ByVal Factorial As System.Double, ByVal TotalCalculations As System.Double) Handles Calculator1.FactorialComplete
        ' Displays the returned value in the appropriate label.
        lblFactorial1.Text = Factorial.ToString
        ' Re-enables the button so it can be used again.
        btnFactorial1.Enabled = True
        ' Updates the label that displays the total calculations performed
        lblTotalCalculations.Text = "TotalCalculations are " & _
           TotalCalculations.ToString
    End Sub
    
    Private Sub Calculator1_FactorialMinusComplete(ByVal Factorial As System.Double, ByVal TotalCalculations As System.Double) Handles Calculator1.FactorialMinusComplete
        lblFactorial2.Text = Factorial.ToString
        btnFactorial2.Enabled = True
        lblTotalCalculations.Text = "TotalCalculations are " & _
            TotalCalculations.ToString
    End Sub
    
    Private Sub Calculator1_LoopComplete(ByVal TotalCalculations As System.Double, ByVal Counter As System.Int32) Handles Calculator1.LoopComplete
        btnRunLoops.Enabled = True
        lblRunLoops.Text = Counter.ToString
        lblTotalCalculations.Text = "TotalCalculations are " & _
           TotalCalculations.ToString
    End Sub
    
  7. Busque la instrucción End Class en la parte inferior del Editor de código. Inmediatamente encima de esta instrucción, agregue el código siguiente para administrar los clics de los botones:

    Private Sub btnFactorial1_Click(ByVal sender As Object, ByVal e As _
       System.EventArgs) Handles btnFactorial1.Click
       ' Passes the value typed in the txtValue to Calculator.varFact1.
       Calculator1.varFact1 = CInt(txtValue.Text)
       ' Disables the btnFactorial1 until this calculation is complete.
       btnFactorial1.Enabled = False
       Calculator1.Factorial()
    End Sub
    
    Private Sub btnFactorial2_Click(ByVal sender As Object, ByVal e _
       As System.EventArgs) Handles btnFactorial2.Click
       Calculator1.varFact2 = CInt(txtValue.Text)
       btnFactorial2.Enabled = False
       Calculator1.FactorialMinusOne()
    End Sub
    
    Private Sub btnAddTwo_Click(ByVal sender As Object, ByVal e As _
       System.EventArgs) Handles btnAddTwo.Click
       Calculator1.varAddTwo = CInt(txtValue.Text)
       btnAddTwo.Enabled = False
       Calculator1.AddTwo()
    End Sub
    
    Private Sub btnRunLoops_Click(ByVal sender As Object, ByVal e As _
       System.EventArgs) Handles btnRunLoops.Click
       Calculator1.varLoopValue = CInt(txtValue.Text)
       btnRunLoops.Enabled = False
       ' Lets the user know that a loop is running.
       lblRunLoops.Text = "Looping"
       Calculator1.RunALoop()
    End Sub
    

Probar la aplicación

Ha creado un proyecto que incorpora un formulario y un componente capaz de realizar varios cálculos complejos. Aunque no haya implementado aún la capacidad de subprocesamiento múltiple, probará el proyecto para comprobar su funcionalidad antes de seguir adelante.

Para probar el proyecto

  1. En el menú Depurar, elija Iniciar depuración. La aplicación se inicia y aparece frmCalculations.

  2. En el cuadro de texto, escriba 4 y, a continuación, haga clic en el botón Agregar dos.

    La etiqueta que aparece debajo debe mostrar el número "6" y "Total Calculations are 1" debe aparecer en lblTotalCalculations.

  3. Ahora, haga clic en el botón con la etiqueta Factorial - 1.

    Debería aparecer el numeral "6" debajo del botón, y "Total Calculations are 4" en lblTotalCalculations.

  4. Cambie el valor del cuadro de texto a 20 y, a continuación, haga clic en el botón Factorial.

    Debería aparecer el número "2.43290200817664E+18" debajo del botón, y "Total Calculations are 24" en lblTotalCalculations.

  5. Cambie el valor del cuadro de texto a 50000; a continuación, haga clic en el botón denominado Ejecutar un bucle.

    Observe que hay un pequeño pero perceptible intervalo antes de que el botón vuelva a estar habilitado. La etiqueta bajo este botón debería indicar "50000" y el total de cálculos mostrado debería ser "25000024".

  6. Cambie el valor del cuadro de texto a 5000000 y haga clic en el botón Ejecutar un bucle; a continuación, haga clic inmediatamente en el botón Agregar dos. Haga clic de nuevo en Agregar dos.

    El botón no responde, ni lo hará ningún control del formulario hasta que el bucle haya finalizado.

    Si el programa ejecuta sólo un subproceso de ejecución, los cálculos que precisan un gran trabajo por parte del procesador, como en el ejemplo anterior, tienden a acaparar el programa hasta que han acabado los cálculos. En la sección siguiente, agregará la capacidad de subprocesamiento múltiple a la aplicación de forma que varios subprocesos puedan ejecutarse a la vez.

Agregar capacidad de subprocesamiento múltiple

El ejemplo anterior mostraba las limitaciones de las aplicaciones que ejecutan un único subproceso. En la sección siguiente, utilizará el objeto de clase Thread para agregar varios subprocesos de ejecución al componente.

Para agregar la subrutina Threads

  1. Abra Calculator.vb en el Editor de código . Cerca de la parte superior del código, busque la línea Public Class Calculator . Inmediatamente a continuación, escriba lo siguiente:

    ' Declares the variables you will use to hold your thread objects.
    Public FactorialThread As System.Threading.Thread
    Public FactorialMinusOneThread As System.Threading.Thread
    Public AddTwoThread As System.Threading.Thread
    Public LoopThread As System.Threading.Thread
    
  2. Justo antes de la instrucción End Class, en la parte inferior del código, agregue el método siguiente:

    Public Sub ChooseThreads(ByVal threadNumber As Integer)
    ' Determines which thread to start based on the value it receives.
       Select Case threadNumber
          Case 1
             ' Sets the thread using the AddressOf the subroutine where
             ' the thread will start.
             FactorialThread = New System.Threading.Thread(AddressOf _
                Factorial)
             ' Starts the thread.
             FactorialThread.Start()
          Case 2
             FactorialMinusOneThread = New _
                System.Threading.Thread(AddressOf FactorialMinusOne)
             FactorialMinusOneThread.Start()
          Case 3
             AddTwoThread = New System.Threading.Thread(AddressOf AddTwo)
             AddTwoThread.Start()
          Case 4
             LoopThread = New System.Threading.Thread(AddressOf RunALoop)
             LoopThread.Start()
       End Select
    End Sub
    

    Cuando se crea una instancia de un objeto Thread, ésta requiere un argumento en la forma de un objeto ThreadStart. El objeto ThreadStart es un delegado que señala a la dirección del método donde debe comenzar el subproceso. Un objeto ThreadStart no puede tener parámetros o pasar valores, y por tanto, no puede indicar una función. El operador AddressOf (Operador) devuelve un delegado que sirve como el objeto ThreadStart. El método ChooseThreads que acaba de implementar recibirá un valor del programa que lo ha llamado y usará ese valor para determinar el subproceso determinado que debe iniciar.

Para agregar el código de inicio de subproceso a frmCalculations

  1. Abra el archivo frmCalculations.vb en el Editor de código. Busque Sub btnFactorial1_Click.

    1. Convierta en comentario la línea que llama al método Calculator1.Factorialdirectamente, como se muestra a continuación:

      ' Calculator1.Factorial
      
    2. Agregue la línea siguiente para llamar al método Calculator1.ChooseThreads:

      ' Passes the value 1 to Calculator1, thus directing it to start the ' correct thread.
      Calculator1.ChooseThreads(1)
      
  2. Haga modificaciones similares en el resto de las subrutinas button_click.

    Nota:

    Asegúrese de incluir el valor apropiado para el argumento threads.

    Cuando haya finalizado, el código deberá ser similar al siguiente:

    Private Sub btnFactorial1_Click(ByVal sender As Object, ByVal e As _
       System.EventArgs) Handles btnFactorial1.Click
       ' Passes the value typed in the txtValue to Calculator.varFact1.
       Calculator1.varFact1 = CInt(txtValue.Text)
       ' Disables the btnFactorial1 until this calculation is complete.
       btnFactorial1.Enabled = False
       ' Calculator1.Factorial()
       ' Passes the value 1 to Calculator1, thus directing it to start the
       ' Correct thread.
       Calculator1.ChooseThreads(1)
    End Sub
    
    Private Sub btnFactorial2_Click(ByVal sender As Object, ByVal e As _
       System.EventArgs) Handles btnFactorial2.Click
       Calculator1.varFact2 = CInt(txtValue.Text)
       btnFactorial2.Enabled = False
       ' Calculator1.FactorialMinusOne()
       Calculator1.ChooseThreads(2)
    End Sub
    
    Private Sub btnAddTwo_Click(ByVal sender As Object, ByVal e As _
       System.EventArgs) Handles btnAddTwo.Click
       Calculator1.varAddTwo = CInt(txtValue.Text)
       btnAddTwo.Enabled = False
       ' Calculator1.AddTwo()
       Calculator1.ChooseThreads(3)
    End Sub
    
    Private Sub btnRunLoops_Click(ByVal sender As Object, ByVal e As _
       System.EventArgs) Handles btnRunLoops.Click
       Calculator1.varLoopValue = CInt(txtValue.Text)
       btnRunLoops.Enabled = False
       ' Lets the user know that a loop is running.
       lblRunLoops.Text = "Looping"
       ' Calculator1.RunALoop()
       Calculator1.ChooseThreads(4)
    End Sub
    

Llamadas de cálculo de referencias a controles

A continuación, facilitará la actualización de la presentación del formulario. Como es el subproceso de ejecución principal el que posee siempre los controles, cualquier llamada a un control de un subproceso secundario requiere utilizar una llamada auxiliar de cálculo de referencias (marshaling). El cálculo de referencias es el acto de pasar una llamada a través de límites de subprocesos y consume muchos recursos. Para minimizar los cálculos de referencias necesarios, y para garantizar que las llamadas se administran de un modo seguro desde el punto de vista de los subprocesos, se utiliza el método BeginInvoke para invocar métodos en el subproceso de ejecución principal, reduciendo así la cantidad de cálculos de referencias entre los límites de los subprocesos que se deben producir. Este tipo de llamada es necesaria cuando se llama a métodos que manipulan controles. Para obtener más información, vea Cómo: Manipular controles a partir de subprocesos.

Para crear los procedimientos que invocan a controles

  1. Abra el Editor de código para frmCalculations. En la sección de declaraciones, agregue el siguiente código:

    Public Delegate Sub FHandler(ByVal Value As Double, ByVal _
       Calculations As Double)
    Public Delegate Sub A2Handler(ByVal Value As Integer, ByVal _
       Calculations As Double)
    Public Delegate Sub LDhandler(ByVal Calculations As Double, ByVal _
       Count As Integer)
    

    Los métodos Invoke y BeginInvoke requieren un delegado del método correspondiente como argumento. Estas líneas declaran las firmas de delegado que utilizará BeginInvoke para invocar los métodos correspondientes.

  2. Agregue los siguientes métodos vacíos al código.

    Public Sub FactHandler(ByVal Factorial As Double, ByVal TotalCalculations As _
       Double)
    End Sub
    Public Sub Fact1Handler(ByVal Factorial As Double, ByVal TotalCalculations As _
       Double)
    End Sub
    Public Sub Add2Handler(ByVal Result As Integer, ByVal TotalCalculations As _
       Double)
    End Sub
    Public Sub LDoneHandler(ByVal TotalCalculations As Double, ByVal Counter As _
       Integer)
    End Sub
    
  3. En el menú Edición, utilice Cortar y Pegar para cortar todo el código de Sub Calculator1_FactorialComplete y pegarlo en FactHandler.

  4. Repita el paso anterior para Calculator1_FactorialMinusComplete, Fact1Handler, Calculator1_AddTwoComplete, Add2Handler, Calculator1_LoopComplete y LDoneHandler.

    Cuando haya finalizado no debería quedar código en Calculator1_FactorialComplete, Calculator1_FactorialMinusComplete, Calculator1_AddTwoComplete y Calculator1_LoopComplete, y todo el código que contuvieran debería haberse movido a los correspondientes métodos nuevos.

  5. Llame al método BeginInvoke para invocar a los métodos de forma asincrónica. Puede llamar al método BeginInvoke desde el formulario (me) o desde cualquiera de los controles del formulario:

    Private Sub Calculator1_FactorialComplete(ByVal Factorial As System.Double, ByVal TotalCalculations As System.Double) Handles Calculator1.FactorialComplete
       ' BeginInvoke causes asynchronous execution to begin at the address
       ' specified by the delegate. Simply put, it transfers execution of 
       ' this method back to the main thread. Any parameters required by 
       ' the method contained at the delegate are wrapped in an object and 
       ' passed. 
       Me.BeginInvoke(New FHandler(AddressOf FactHandler), New Object() _
          {Factorial, TotalCalculations })
    End Sub
    
    Private Sub Calculator1_FactorialMinusComplete(ByVal Factorial As System.Double, ByVal TotalCalculations As System.Double) Handles Calculator1.FactorialMinusComplete
       Me.BeginInvoke(New FHandler(AddressOf Fact1Handler), New Object() _
          { Factorial, TotalCalculations })
    End Sub
    
    Private Sub Calculator1_AddTwoComplete(ByVal Result As System.Int32, ByVal TotalCalculations As System.Double) Handles Calculator1.AddTwoComplete
       Me.BeginInvoke(New A2Handler(AddressOf Add2Handler), New Object() _
          { Result, TotalCalculations })
    End Sub
    
    Private Sub Calculator1_LoopComplete(ByVal TotalCalculations As System.Double, ByVal Counter As System.Int32) Handles Calculator1.LoopComplete
       Me.BeginInvoke(New LDHandler(AddressOf Ldonehandler), New Object() _
          { TotalCalculations, Counter })
    End Sub
    

    Puede parecer que el controlador de eventos está haciendo sólo una llamada al método siguiente. Sin embargo, da lugar a que se invoque un método en el subproceso principal. Este sistema ahorra llamadas fuera de los límites de los subprocesos y permite a las aplicaciones multiproceso ejecutarse de forma eficiente y sin peligro de que se produzcan bloqueos. Para obtener más detalles sobre cómo trabajar con controles en un entorno multiproceso, vea Cómo: Manipular controles a partir de subprocesos.

  6. Guarde su trabajo.

  7. Pruebe la solución; para ello, en el menú Depurar elija Iniciar depuración.

    1. Escriba 10000000 en el cuadro de texto y haga clic en Ejecutar un bucle.

      Aparecerá "Looping" en la etiqueta situada debajo del botón. Este bucle debe tardar un tiempo considerable en ejecutarse. Si finaliza demasiado pronto, ajuste el tamaño del número en consecuencia.

    2. En una sucesión rápida, haga clic en los tres botones que están habilitados. Verá que todos los botones responden a su acción. La etiqueta situada debajo de Agregar dos debería ser la primera en mostrar un resultado. Los resultados se mostrarán posteriormente en las etiquetas situadas debajo de los botones factoriales. Estos resultados se evalúan a infinito, ya que el número devuelto por un factorial 10.000.000 es demasiado grande para que lo contenga una variable de doble precisión. Finalmente, después de un intervalo adicional, los resultados se devuelven debajo del botón Ejecutar un bucle.

      Como habrá podido observar, se han realizado cuatro conjuntos de cálculos independientes de forma simultánea en cuatro subprocesos independientes. La interfaz de usuario permanece receptiva a las entradas y los resultados se devolvieron después de que finalizara cada subproceso.

Coordinar los subprocesos

Un usuario con experiencia en aplicaciones multiproceso puede percibir un sutil defecto con el código tal y como está escrito. Recuerde las líneas de código de cada subrutina de realización de cálculos de Calculator:

varTotalCalculations += 1
varTotalAsOfNow = varTotalCalculations

Estas dos líneas de código incrementan la variable pública varTotalCalculations y asignan su valor a la variable local varTotalAsOfNow este valor. Dicho valor se devuelve a frmCalculations y se muestra en un control de etiqueta. Pero no se sabe si el valor es correcto. Si sólo se está ejecutando un subproceso, la respuesta claramente es sí. Pero si se están ejecutando varios subprocesos, la respuesta se vuelve incierta. Cada subproceso tiene la capacidad de incrementar la variable varTotalCalculations. Por tanto, es posible que, después de que un subproceso incremente esta variable, pero antes de que copie el valor en varTotalAsOfNow, otro subproceso altere el valor de esta variable incrementándolo. Esto nos lleva a la posibilidad de que cada subproceso está, en realidad, suministrando resultados inexactos. Visual Basic proporciona la instrucción SyncLock (Instrucción) para permitir la sincronización de los subprocesos con el fin de garantizar que cada uno de ellos devuelva siempre un resultado exacto. La sintaxis de SyncLock es la siguiente:

SyncLock AnObject
   Insert code that affects the object
   Insert some more
   Insert even more
' Release the lock
End SyncLock

Cuando se entra en el bloque SyncLock, la ejecución sobre la expresión especificada se bloquea hasta que el subproceso especificado dispone de un bloqueo exclusivo sobre el objeto en cuestión. En el ejemplo anterior, la ejecución se bloquea en AnObject. El bloque SyncLock se debe utilizar con un objeto que devuelva una referencia en vez de un valor. Entonces, la ejecución puede continuar como un bloque sin interferencias de otros subprocesos. Un conjunto de instrucciones que se ejecutan como una unidad se denomina atómico. Cuando se encuentra End SyncLock, se libera la expresión y se permite a los subprocesos ejecutarse normalmente.

Para agregar la instrucción SyncLock a la aplicación

  1. Abra Calculator.vb en el Editor de código .

  2. Busque todas las instancias del código siguiente:

    varTotalCalculations += 1
    varTotalAsOfNow = varTotalCalculations
    

    Debería haber cuatro instancias de este código, una en cada método de cálculo.

  3. Modifique este código de modo que sea como el siguiente:

    SyncLock Me
       varTotalCalculations += 1
       varTotalAsOfNow = varTotalCalculations
    End SyncLock
    
  4. Guarde el trabajo y pruébelo como en el ejemplo anterior.

    Puede notar un leve impacto en el rendimiento del programa. Esto se debe a que la ejecución de los subprocesos se detiene cuando se obtiene un bloque exclusivo en el componente. Aunque esto asegura la exactitud, impide aprovechar algunas de las ventajas de los subprocesos múltiples. Por tanto, debería considerar concienzudamente la necesidad de bloquear los subprocesos e implementarlos sólo cuando sea absolutamente necesario.

Vea también

Tareas

Cómo: Coordinar varios subprocesos de ejecución

Tutorial: Crear un componente sencillo con múltiples procesos en Visual C#

Conceptos

Información general sobre el modelo asincrónico basado en eventos

Referencia

BackgroundWorker

Otros recursos

Programar con componentes

Tutoriales sobre la programación de componentes

Subprocesamiento múltiple en componentes