2009-10-23 14 views
7

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 de 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 pueda iniciar la sincronización pero cuando se ejecute cada otro subproceso que intentará comenzar, terminará.C# bloqueo y advertencia de análisis de código CA2002

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 está funcionando bien pero cuando corro análisis de código en mi proyecto estoy recibiendo el siguiente mensaje de advertencia:

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

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

Respuesta

10

Lo que está mal es que está bloqueando algo público (typeof(SynchronizationForm)) al que se puede acceder desde cualquier lugar desde su código y si otro hilo se bloquea en esta misma situación se produce un interbloqueo. En general, es una buena idea para bloquear sólo en objetos estáticos privados:

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

} 

Esto le garantiza que sólo es SynchronizationForm que podrían poseer la cerradura.

+1

Esto es cierto, pero el bloqueo de objetos con "identidad débil" tampoco es aconsejable por otras razones. –

6

Desde el MSDN explanation of the rule

Un objeto se dice que tiene una identidad débil cuando se puede acceder directamente a través de los límites del dominio de 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 tiene un bloqueo en el mismo objeto.

Dado que no se puede predecir necesariamente qué bloqueos podría tener otro dominio de aplicación, y dado que dichos bloqueos podrían tener que organizarse y resultar costosos, esta regla tiene sentido para mí.

3

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

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

Entonces se producirá un interbloqueo. En su lugar, debe descuidar un objeto de bloqueo privado en la clase SynchronizationForm y bloquearlo en su lugar.

2

El objeto System.Type de una clase se puede usar convenientemente como bloqueo mutuo de exclusión para métodos estáticos de la clase.

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

Para añadir a la respuesta de Doug, lo que tenemos aquí es un mecanismo de bloqueo que sólo debe ser utilizado en los métodos estáticos, siendo utilizado en un método de instancia.

+1

Bloquear en System.Type ya no se considera una buena práctica, por las razones dadas en MSDN por el enlace en la respuesta de Doug. Idealmente, esa declaración y el ejemplo del código se eliminarían de la especificación del lenguaje C#. –

Cuestiones relacionadas