Volatile DateTime

Поскольку DateTime нельзя объявить изменчивым, это правильно?:

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

Это свойство можно получить из разных потоков, поэтому я хочу, чтобы они всегда получали последнюю версию, без использования конкуренции (блокировки).

EDIT:

  • У меня есть набор труднодоступных элементов, каждый из которых имеет свойство DateTime с именем CreationTime, указывающее, когда этот элемент был создан. Он инициализирован DateTime.UtcNow.
  • При каждом доступе элемента это свойство обновляется до DateTime.UtcNow.
  • Существует поток, который выполняется своевременно в поточном таймере, который проверяет (DateTime.UtcNow + 1 час) > item.CreationTime, если true, он удаляет элемент.

Я хочу убедиться, что, когда в сборник входит "поток делегирования", все элементы имеют на нем свой последний "последний доступ" DateTime, поэтому я могу избежать создания элемента снова только потому, что в кеше было значение для пара миллисекунд: D

Спасибо заранее.

Ответ 1

Точно.

Но у вас есть другой вариант. Храните время в виде количества меток Int64 и используйте InterlockedExchange для установки. Затем потоки могут создавать свои собственные DateTime, используя конструктор Int64, не давая вам никаких споров и никаких блокировок.

EDIT:

Учитывая, что вы предоставили больше информации, теперь проще привести пример.

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

Ответ 2

Это невозможно - вам нужно будет использовать класс lock или Monitor для синхронизации доступа к полю.

Это потому, что DateTime - тип значения - структура.

Из MSDN - volatile (ссылка на С#):

Ключевое слово volatile может применяться к полям этих типов:

  • Типы ссылок.
  • Типы указателей (в небезопасном контексте). Обратите внимание, что хотя сам указатель может быть изменчивым, объект, на который указывает указывает, не может. Другими словами, вы не можете объявить "указатель на volatile".
  • Типы, такие как sbyte, byte, short, ushort, int, uint, char, float и bool.
  • Тип перечисления с одним из следующих базовых типов: byte, sbyte, short, ushort, int или uint.
  • Параметры типового типа, известные как ссылочные типы.
  • IntPtr и UIntPtr.

Как уже упоминалось, вы можете использовать Ticks для отслеживания времени.

Ответ 3

Ваш код не является потокобезопасным, поскольку присвоение DateTime не гарантируется атомарным. В общем случае назначения целых чисел до 32 бит являются атомарными, но 64 не обязательно должны быть атомарными.

Вероятно, вы можете использовать Interlocked.Exchange с тиками DateTime, так как это может атомно хранить Int64.

Но если вы переключаетесь на тики, вам нужно знать, что для тиков используются только 62 бита и 2 бит для такого типа. Таким образом, вы не потеряете своего рода.

И даже если вы сделаете getter и setter atomic потокобезопасными, я не уверен, достаточно ли этого. Поскольку время может измениться между временем, в которое возвращается ваш геттер, и временем, которое вы действительно работаете с временем, которое вы получили. Таким образом, ваше время всегда может быть устаревшим.