Pregunta

En mi aplicación tengo un formulario que inicia el proceso de sincronización y, por varias razones, quiero permitir que solo se ejecute una sincronización a la vez. Así que agregué un campo bool estático a mi formulario que indica si la sincronización está en progreso y agregué un bloqueo para establecer este campo en verdadero si aún no estaba configurado para que el primer subproceso pudiera comenzar la sincronización, pero cuando se ejecuta cada otro subproceso que intentará iniciarlo terminará.

Mi código es algo como esto:

internal partial class SynchronizationForm : Form
{
    private static volatile bool workInProgress;

    private void SynchronizationForm_Shown(object sender, EventArgs e)
    {
        lock (typeof(SynchronizationForm))
        {
            if (!workInProgress)
            {
                workInProgress = true;
            }
            else
            {
                this.Close();
            }
        }
    }
}

Esto funciona bien, pero cuando ejecuto Code Analysis en mi proyecto recibo el siguiente mensaje de advertencia:

  

CA2002: Microsoft.Reliability: 'SynchronizationForm.SynchronizationForm_Shown (object, EventArgs)' se bloquea en una referencia de tipo 'Tipo'. Reemplace esto con un bloqueo contra un objeto con identidad fuerte.

¿Alguien puede explicarme qué tiene de malo mi código y cómo puedo mejorarlo para que desaparezca la advertencia? ¿Qué significa que el objeto tiene una identidad fuerte?

¿Fue útil?

Solución

Lo que está mal es que está bloqueando algo público ( typeof (SynchronizationForm) ) al que se puede acceder desde cualquier parte de su código y si algún otro hilo se bloquea en esta misma cosa, se obtiene un punto muerto. En general, es una buena idea bloquear solo los objetos estáticos privados:

private static object _syncRoot = new object();
...
lock (_syncRoot) 
{

}

Esto le garantiza que solo el SynchronizationForm podría poseer el bloqueo.

Otros consejos

Del explicación MSDN de la regla

  

Se dice que un objeto tiene una identidad débil cuando se puede acceder directamente a través de los límites del dominio de la aplicación. Un subproceso que intenta adquirir un bloqueo en un objeto que tiene una identidad débil puede ser bloqueado por un segundo subproceso en un dominio de aplicación diferente que tenga un bloqueo en el mismo objeto.

Dado que no necesariamente puede predecir qué bloqueos podría tener otro AppDomain, y dado que dichos bloqueos deben ser ordenados y luego ser caros, esta regla tiene sentido para mí.

El problema es que typeof (SynchronizationForm) no es un objeto de bloqueo privado, lo que significa que cualquier otro fragmento de código podría usarlo para bloquear, lo que podría provocar un punto muerto. Por ejemplo, si algún otro código hizo esto:

var form = new SynchronizationForm();
lock(typeof(SynchronizationForm))
{
    form.SomeMethodThatCausesSynchronizationForm_ShownToBeCalled();
}

Entonces se producirá un punto muerto. En su lugar, debería eliminar un objeto de bloqueo privado en la clase SynchronizationForm y bloquearlo en su lugar.

  

El objeto System.Type de una clase puede usarse convenientemente como bloqueo de exclusión mutua para los métodos estáticos de la clase.

Fuente: http://msdn.microsoft. com / es-us / library / aa664735 (VS.71) .aspx

Para agregar a la respuesta de Doug, lo que tiene aquí es un mecanismo de bloqueo que solo debe usarse en métodos estáticos, que se usa en un método de instancia.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top