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 потокобезопасными, я не уверен, достаточно ли этого. Поскольку время может измениться между временем, в которое возвращается ваш геттер, и временем, которое вы действительно работаете с временем, которое вы получили. Таким образом, ваше время всегда может быть устаревшим.