2011-06-21 6 views
11

Tengo una clase que está diseñada principalmente como una clase POCO, con varios subprocesos y tareas podrían leer sus valores, y solo otros ocasionalmente actualizando estos valores. Este parece ser un escenario ideal para ReaderWriterLockSlim.Se requiere acceso de bloqueo a un bool o es Overkill

La pregunta es, en la clase, si la propiedad que necesita ser segura para subprocesos, si la propiedad es un bool, ¿es esa exageración? ¿Qué pasa si es un int? ¿Fecha y hora?

public class MyClass 
{ 
    private bool _theValue = false; 
    private ReaderWriterLockSlim _theValueLock = new ReaderWriterLockSlim(); 

    public bool TheValue 
    { 
    get 
    { 
     bool returnVal = false; 
     try 
     { 
     _theValueLock.EnterReadLock(); 
     returnVal = _theValue; 
     } 
     finally 
     { _theValueLock.ExitReadLock(); } 
     return returnVal; 
    } 
    set 
    { 
     try 
     { 
     _theValueLock.EnterWriteLock(); 
     _theValue = value; 
     } 
     finally 
     { _theValueLock.ExitWriteLock(); } 
    } 
    } 
} 

Es todo este código exageración, y un simple ...

public bool TheValue { get; set; } 

... sería suficiente? Porque el tipo es bool, ¿es seguro? si es así, ¿cuándo no se vuelve seguro? byte? ¿En t? ¿Fecha y hora?

edición
Mi arquitectura básica es tener este estado almacenamiento de clases. Tal vez tenga un servicio a cargo de hacer las escrituras en esta clase. Todas las demás clases pueden leer y realizar su lógica en función de estos datos de estado. Haré todo lo posible para asegurarme de que todos los datos sean consistentes, pero como se indica a continuación, mi principal preocupación fue la atomicidad y la fragmentación de los datos.

Conclusión
Gracias a todos por su respuesta, todas fueron valiosas. Mi principal preocupación era la atomicidad de las escrituras/lecturas (es decir, preocupado por las férulas). Para la plataforma .NET, si la variable en cuestión es un tipo de valor incorporado que tiene menos de 4 bytes, la lectura y la escritura son atómicas (por ejemplo, short e int son finas, long y double no).

+1

No protegerlo es muy pesado debajo de matar. No puede obtener una respuesta precisa sin mostrar cómo se usa la propiedad. Bloquear en el nivel de propiedad muy raramente funciona. –

+1

más para mi propia referencia algunos enlaces [link] (http://www.albahari.com/threading/) las mejores prácticas sobre el enhebrado, [link] (http://blogs.msdn.com/b/ericlippert/archive/ 2011/05/26/atomicity-volatility-and-immutability-are-different-part-one.aspx) atmoicity, voltile gracias a @brian, [link] (http://blogs.msdn.com/b/brada/ archive/2003/04/03/49896.aspx) lectura rápida en atomicity gracias a @reed – Andre

+0

Como nota personal, escuchando dnr.tv y el comentario de jon skeet sobre bloqueo de bools, busqué este http://askjonskeet.com/answer/6873994/Boolean-Property-Getter-and-Setter-Locking, que básicamente dice que, en escenarios de subprocesos múltiples, podría ser una buena idea bloquearlo. – Andre

Respuesta

3

Tiene algunas opciones.

  • No hacer nada.
  • Haz que la clase sea inmutable.
  • Utilice un simple viejo lock.
  • Marque los campos como volatile.
  • Utilice el conjunto de métodos Interlocked.

Ya que las lecturas y escrituras en un bool son atómicas, es posible que no necesite hacer nada. Esto dependerá en gran medida de la naturaleza de la forma en que va a usarse su clase. La atomicidad no es igual a la seguridad de las hebras. Es solo un aspecto de eso.

La solución ideal es hacer que su clase sea inmutable. Las clases inmutables generalmente son seguras para subprocesos porque no pueden ser modificadas por otros subprocesos (o en absoluto). A veces esto simplemente no es factible.

Mi siguiente preferencia en la lista es un simple viejo lock. La sobrecarga de adquirir y liberar es muy mínima. De hecho, creo que encontrará que un lock superará un ReaderWriterLockSlim en la mayoría de las situaciones, especialmente si todo lo que hace es leer/escribir una variable. Mis propias pruebas personales indican que la sobrecarga de RWLS es aproximadamente 5x más lenta que que lock. Entonces, a menos que las operaciones de lectura sean inusualmente largas y que superen significativamente las operaciones de escritura, RWLS no ayudará.

Si le preocupa la sobrecarga del bloqueo, marque los campos como volatile. Solo recuerda que volatile no es una bala mágica que resuelve todos los problemas de concurrencia. No pretende ser un reemplazo para lock.

8

Dependiendo de cómo se use esto, es posible que deba marcar la booleana volatile. Esto requerirá un campo de respaldo para su propiedad.

No debería ser necesario para manejar esto con el ReaderWriterLockSlim como que está haciendo ahora, ya que es menos de 32 bits (suponiendo que está utilizando diseño automático, para más detalles, véase this post o, en su mayor detalle, la sección titulada La atomicidad de la memoria tiene acceso a en la especificación ECMA 335). Si usa un tipo más grande que este, entonces se requerirá alguna forma de sincronización.

yo recomendaría:

public class MyClass 
{ 
    private volatile bool _theValue = false; 
    public bool TheValue 
    { 
     get { return _theValue; } 
     set { _theValue = value; } 
    } 
} 
+1

Como habrás notado, el acceso a un 'bool' ya es atómico. Pero 'volátil' no proporcionará ninguna sincronización o seguridad de hilos. – user7116

+1

@sixlettervariables: Es cierto, pero la solución de OP de bloqueo alrededor de una única propiedad solo es útil para garantizar la atomicidad: tampoco hubo sincronización ni seguridad de subprocesos en la solución original. Este es un reemplazo * aceptable en este caso *. –

+0

es suficiente. Aunque su solución original con el bloqueo proporcionaría acceso seguro a subprocesos con RWLS. – user7116

4

Ningún tipo es verdaderamente seguro! Más precisamente, las especificaciones de C# le aseguran que la lectura o la asignación de tipos de estructura de menos de 4 bytes o referencias son atómicos. si su sistema operativo es de 64 bits, CLR lo hace un poco mejor al asegurar lo mismo para estructuras de menos de 8 bytes.

Pero cualquier cosa más complicada que una asignación o una lectura de un valor puede potencialmente ser interrumpida por otro hilo competidor si no tiene cuidado.

Incluso algo tan simple como esto:

myBool = !myBool 

puede obtener un resultado inesperado si un hilo competir modificar el valor de myBool.

Se recomienda el uso de cerraduras si desea estar seguro de que algo así no ocurra.El uso de la palabra clave volátil es desaconsejado a menos que sepa exactamente lo que está haciendo. Verifique theseblogposts para obtener información adicional.

Sin embargo, en su ejemplo, donde la propiedad no hace más que una sola escritura o una sola lectura, el bloqueo es inútil. Pero no sería si hubiera algún tratamiento adicional.

+1

Emphesizing your example. En su ejemplo, usted lee y escribe al mismo tiempo, mientras que myBool = true solo escribe.Por lo tanto, volátil no es suficiente para myBool =! MyBool – liorafar

Cuestiones relacionadas