Compartir a través de


Componentes seguros para subprocesos

Actualización: noviembre 2007

Compartir recursos entre subprocesos constituye una necesidad frecuente en la programación multiproceso. Por ejemplo, es posible que varios subprocesos necesiten obtener acceso a una base de datos compartida, o actualizar un conjunto de variables del sistema. Cuando más de un subproceso compite simultáneamente por obtener acceso a recursos compartidos existe la posibilidad de que se produzca una condición de anticipación. Existe una condición de anticipación cuando un subproceso modifica un recurso y lo deja en un estado no válido y, a continuación, otro subproceso intenta obtener acceso a ese recurso y usarlo en dicho estado no válido. Considere el ejemplo siguiente:

Public Class WidgetManipulator
Public TotalWidgets as Integer = 0
Public Sub AddWidget()
   TotalWidgets += 1
   Console.WriteLine("Total widgets = " & TotalWidgets.ToString)
End Sub
Public Sub RemoveWidgets()
   TotalWidgets -= 10
End Sub
End Class
public class WidgetManipulator
{
   public int TotalWidgets = 0;
   public void AddWidget()
   {
      TotalWidgets++;
      Console.WriteLine("Total widgets = " + TotalWidgets.ToString());
   }
   public void RemoveWidgets()
   {
      TotalWidgets -= 10;
   }
}

Esta clase expone dos métodos. Un método, AddWidget, suma 1 al campo TotalWidgets y escribe el valor en la consola. El segundo método resta 10 del valor de TotalWidgets. Considere lo que ocurriría si dos subprocesos intentaran obtener acceso simultáneamente a la misma instancia de la clase WidgetManipulator. Un subproceso podría llamar a AddWidget al mismo tiempo que el segundo subproceso llama a RemoveWidgets. En ese caso, el valor de TotalWidgets podría ser modificado por el segundo subproceso antes de que el primer subproceso pudiera comunicar un valor exacto. Esta condición de anticipación puede hacer que se comuniquen resultados inexactos y puede causar daños en los datos.

Evitar condiciones de anticipación mediante bloqueos

Se pueden proteger las secciones vitales del código de las condiciones de anticipación mediante el uso de bloqueos. Un bloqueo, representado en Visual Basic por la palabra clave SyncLock (Instrucción), o en C# por lock (Instrucción), permite que un único subproceso obtenga derechos de ejecución únicos sobre un objeto. En el ejemplo siguiente se ilustran los bloqueos:

SyncLock MyObject
' Insert code that affects MyObject.
End SyncLock
lock(MyObject)
{
   // Insert code that affects MyObject.
}

Cuando se encuentra un bloqueo, la ejecución en el objeto especificado (MyObject en el ejemplo anterior) se bloquea hasta que el subproceso pueda obtener acceso único al objeto. Cuando se alcanza el fin del bloqueo, éste se libera y la ejecución procede de forma normal. Sólo se puede obtener un bloqueo sobre un objeto que devuelva una referencia. Un tipo de valor no se puede bloquear de este modo.

Desventajas de los bloqueos

Aunque los bloqueos garantizan que varios subprocesos no obtengan acceso simultáneamente a un objeto, pueden causar una degradación importante del rendimiento. Imagínese un programa con muchos subprocesos distintos ejecutándose. Si cada subproceso necesita usar un objeto determinado y tiene que esperar para obtener un bloqueo único sobre dicho objeto antes de ejecutarse, todos los subprocesos dejarán de ejecutarse y harán cola uno detrás de otro, produciendo un rendimiento muy bajo. Por estas razones, sólo se deberían usar bloqueos cuando haya código que debe ejecutarse como una unidad. Por ejemplo, podría actualizar varios recursos que sean interdependientes. Este código se conoce como atómico. Si los bloqueos se restringen sólo al código que se deba ejecutar de forma atómica, se podrán escribir componentes multiproceso que garanticen la seguridad de los datos a la par que un buen rendimiento.

Asimismo, debe tener cuidado para evitar situaciones en las que puedan producirse interbloqueos. Este caso se produce cuando existen al menos dos subprocesos que están esperando a que el otro libere ciertos recursos compartidos. Por ejemplo, el subproceso 1 puede alojar un boqueo en el recurso A y estar esperando al recurso B. El subproceso 2, por otro lado, puede tener un bloqueo en el recurso B y estar esperando al recurso A. En este caso, ninguno de los dos subprocesos podrá continuar. La única forma de evitar situaciones de interbloqueo es mediante una programación cuidadosa.

Vea también

Tareas

Cómo: Coordinar varios subprocesos de ejecución

Cómo: Manipular controles a partir de subprocesos

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

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

Subprocesamiento múltiple en componentes