2011-01-28 27 views
10

Como DateTime no pueden ser declarados como volátil, es este derecho ?:DateTime volátil

 private DateTime _time; 
     public DateTime Time 
     { 
      get 
      { 
       Thread.MemoryBarrier(); 
       return _time; 
      } 
      set 
      { 
       _time = value; 
       Thread.MemoryBarrier(); 
      } 
     } 

Esa propiedad se podría acceder desde diferentes hilos, por lo que quiero asegurar que incluyen siempre la última versión, sin el uso de contención (bloquear).

EDIT:

  • tengo una colección de difíciles de crear elementos, cada uno tiene una propiedad DateTime llamado CreationTime, lo que indica que se creó este artículo. Se inicializa a DateTime.UtcNow.
  • Cada vez que se accede a un elemento, esa propiedad se actualiza a DateTime.UtcNow.
  • Hay un hilo, que se ejecuta de manera oportuna en un temporizador con hebras que comprueba si (DateTime.UtcNow + 1 hora)> item.CreationTime, si es verdadero, elimina el elemento.

Quiero asegurarme de que cuando el "hilo de eliminación" entra en la colección, todos los elementos tengan su último "último acceso" DateTime, así puedo evitar crear el elemento nuevamente solo porque un caché contenía el valor por un par de milisegundos: D

Gracias de antemano.

+0

No estoy seguro si lo que estás tratando de hacer sentido. ¿Cómo defines la última versión? – CodesInChaos

+0

He actualizado el post – vtortola

+1

Teniendo en cuenta que va a implementar una memoria caché de objetos que elimina un-usado de más de un período de tiempo determinado, creo que la solución 'InterlockedExchange' es el camino a seguir aquí. –

Respuesta

12

Precisamente.

Pero tiene otra opción. Almacene el tiempo como un conteo de ticks Int64, y use InterlockedExchange para establecer. Los subprocesos pueden construir su propio DateTime usando el constructor Int64, sin conflictos ni bloqueos.

EDIT:

Teniendo en cuenta que usted ha proporcionado más información, es más fácil ahora que sirva de ejemplo.

public class Cache 
{ 
    class CacheEntry 
    { 
     private Int64 m_Touched; 

     public CacheEntry() 
     { 
      Touch(); 
     } 

     public void Touch() 
     { 
      System.Threading.Interlocked.Exchange(ref m_Touched, DateTime.Now.Ticks); 
     } 

     public DateTime Touched 
     { 
      get 
      { 
       return new DateTime(Interlocked.Read(ref m_Touched)); 
      } 
     } 
    } // eo class CacheEntry 
} // eo class Cache 
+3

Es mejor utilizar 'ToBinary' /' FromBinary' en lugar de simplemente almacenar los ticks sin procesar, de modo que también se preserve 'DateTimeKind'. (Aunque yo diría que el OP debe, probablemente, sólo tiene que utilizar un 'lock' y una llanura' DateTime' lugar de tratar de ser demasiado inteligente.) – LukeH

+2

Aunque es posible, tanto de estas sugerencias suena como que podría haber una gran cantidad de redundancia conversiones involucradas. Eso, por supuesto, depende de cuántos consumidores tenga ese valor de DateTime. –

+2

@ Sensai76, quizás, pero dudo que la conversión vaya a ser una carga problemática (aunque es difícil de decir sin saber cómo esto es utilizado por los otros hilos), y dicho esto, será menos de una sobrecarga que algún tipo de bloquear. –

2

Esto no es posible: deberá usar lock o la clase Monitor para sincronizar el acceso al campo.

Esto es porque DateTime es un tipo de valor - una estructura.

De MSDN - volatile (C# Reference):

La palabra clave volátil se puede aplicar a los campos de este tipo:

  • Tipos de referencia.
  • Tipos de puntero (en un contexto inseguro). Tenga en cuenta que aunque el puntero en sí mismo puede ser volátil, el objeto al que apunta no puede. En otras palabras, no puede declarar un "puntero a volátil".
  • Tipos como sbyte, byte, short, ushort, int, uint, char, float y bool.
  • Un tipo de enumeración con uno de los siguientes tipos de base: byte, sbyte, short, ushort, int o uint.
  • Parámetros genéricos de tipo conocidos por ser tipos de referencia.
  • IntPtr y UIntPtr.

Como otros han mencionado, se puede utilizar para medir el tiempo Ticks.

2

El código no es seguro para subprocesos ya que la asignación de DateTime no se garantiza que sea atómica. En general, las asignaciones de enteros de hasta 32 bits son atómicas, pero 64 no necesitan ser atómicas.

Probablemente pueda usar Interlocked.Exchange con los ticks del DateTime, ya que puede almacenar atómicamente un Int64.

Pero si se cambia a las garrapatas que necesita saber que sólo 62 bits se utilizan para las garrapatas, y 2 bits para el tipo. Entonces no pierdes el tipo.

E incluso si se hace el getter y setter atómica un multi-hilo, no estoy seguro si eso es suficiente. Dado que el tiempo puede cambiar entre el momento en que regresa su getter y el momento en que realmente trabaja con el tiempo que recibió. Entonces tu tiempo siempre puede estar desactualizado.

+0

esta es una aplicación x64 para máquinas x64. ¿importa? Buen punto. – vtortola

+0

@vtortola de acuerdo con esto, las asignaciones de 64 bits pueden ser atómicas: _La CLI garantiza que las lecturas y escrituras de variables de tipos de valores que son del tamaño (o menor) del tamaño del puntero natural del procesador son atómicas; si está ejecutando el código C# en un sistema operativo de 64 bits en una versión de 64 bits del CLR, entonces las lecturas y escrituras de dobles de 64 bits y enteros largos también se garantiza que serán atómicas. El lenguaje C# no garantiza eso, pero la especificación de tiempo de ejecución sí lo hace. Https://stackoverflow.com/a/11745471/67824 –