2011-12-29 21 views
5

Estoy implementando una clase que se utilizará al mismo tiempo desde varios subprocesos. La mayoría de las propiedades obtienen y configuran tipos primitivos que la clase Interbloqueada puede manejar adecuadamente. La clase incluye una propiedad Guid. Esto no es tan simple de implementar de una manera segura para subprocesos. ¿Es así como implementarías la propiedad? Gracias por adelantado.¿Es esta la manera correcta de implementar una propiedad Guid de lectura/escritura segura para subprocesos?

private Byte[] _activityId; 
public Guid ActivityId 
    { 
     get { return new Guid(this._activityId); } 
     set 
     { 
      Byte[] bytes = value.ToByteArray(); 
      Interlocked.Exchange(ref this._activityId, bytes); 
     } 
    } 

ACTUALIZACIÓN: Así que la única solución propuesta hasta este punto no incluye el uso de cualquier clase o construcciones "Threading". Así que voy a plantear la pregunta que ya he planteadas en los comentarios:

Mi opinión es que los tipos de referencia/valores primitivos asignaciones son atómicas embargo Interlocked garantizará el cambio se propaga a todas las roscas. Si pudiéramos simplemente asignar el valor, ¿por qué Interlocked expone las API para intercambiar tipos de referencia y valores primitivos?

+3

Las asignaciones de los tipos de referencia son atómicas; no necesitas 'Enclavamiento'. – SLaks

+1

Es muy posible que me falta algo aquí, pero como las Guías son tipos de valores, ¿cuál es exactamente el problema aquí? –

+0

¿Cuál es el punto de tener una propiedad de respaldo 'byte []' y una propiedad 'Guid' pública? ¿Cómo se usará este código? –

Respuesta

2

Creo que se podría utilizar la otra sobrecarga del Interlocked.Exchange:

private volatile object _activityId; // Yes, object :) 
public Guid ActivityId { 
    get { return (Guid)_activityId; } 
    set { _activityId = value; } 
} 

Esto funciona porque el Guid está ahora en caja, y la asignación de los tipos de referencia es atómica.

+1

Eso no compilará; necesitas un elenco Además, todavía no necesitas 'Enclavamiento'. – SLaks

+1

@SLaks Tiene razón: agregué el elenco, eliminé Exchange y agregué una explicación rápida. Gracias por detectar el error (debería haber copiado y pegado desde mi editor en lugar de volver a escribir con un molde perdido). – dasblinkenlight

+0

Parece que podría devolver valores obsoletos del getter. – CodesInChaos

4

Usted puede obtener la asignación atómica más barato en la creación de su propia clase de cuadro:

class Box<T> where T : struct { 
    public readonly T Value; 
    public Box(T value) { Value = value; } 
} 

Al almacenar una referencia a la (inmutable) instancia Box en lugar de almacenar el valor directamente, todas las operaciones en el campo serán atómica .

private Box<Guid> _activityId; 
public Guid ActivityId { 
    get { return this._activityId.Value; } 
    set { this._activityId = new Box<Guid>(value); } 
} 

De esta manera, las operaciones de copia de estructura atómica no suceda en new Box<Guid>(value) y en el .Value acceso. Como no involucran el campo, no causarán problemas.

Esto debería ser mucho más rápido que usar arrays de bytes, y un poco más rápido que el boxeo nativo con un molde. (descargo de responsabilidad: no he medido)

+0

¿Cómo es que no hay necesidad de enclavamiento -o-- el modificador volátil -o- algún otro constructo/clase "Theading"? – Josh

+1

Porque las asignaciones de referencia son atómicas. Es posible que desee 'Thread.MemoryBarrier()'; No estoy seguro. – SLaks

+0

@SLaks: MemoryBarrier() es principalmente importante para garantizar el pedido o asegurarse de que un bucle no optimiza la carga de un valor desde la memoria en lugar de simplemente verificar el registro. Debes estar en lo correcto con tu respuesta. – Bengie

Cuestiones relacionadas