непостоянен DateTime

Тъй като DateTime не може да бъде деклариран като непостоянен, това правилно ли е?:

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

Това свойство може да бъде достъпно от различни нишки, така че искам да се уверя, че те винаги получават най-новата версия, без да използват конкуренция (заключване).

РЕДАКТИРАНЕ:

  • Имам колекция от трудни за създаване елементи, всеки от които има свойство DateTime, наречено CreationTime, което показва кога е създаден този елемент. Инициализира се на DateTime.UtcNow.
  • Всеки път, когато има достъп до елемент, това свойство се актуализира до DateTime.UtcNow.
  • Има нишка, която се изпълнява своевременно в таймер с резба, който проверява дали (DateTime.UtcNow + 1 час) > item.CreationTime, ако е вярно, изтрива елемента.

Искам да се уверя, че когато „нишката за изтриване“ влезе в колекцията, всички елементи имат последния си „последен достъп“ DateTime, така че да мога да избегна повторното създаване на елемента само защото кешът е запазил стойността за няколко милисекунди :Д

Благодаря предварително.


person vtortola    schedule 28.01.2011    source източник
comment
Не съм сигурен дали това, което се опитвате да направите, има смисъл. Как определяте най-новата версия?   -  person CodesInChaos    schedule 28.01.2011
comment
Като се има предвид, че внедрявате кеш, който премахва неизползвани обекти, по-стари от определен период от време, мисля, че решението InterlockedExchange е начинът да отидете тук.   -  person Moo-Juice    schedule 28.01.2011
comment
Знаете, че DateTime.Now е с точност само до 1/64 от секундата, нали? Ако се притеснявате от неточност, дължаща се на забавяне на кеша с милисекунди, значи вече сте загубили; точността на данните, които се опитвате да поддържате точни, е много, много по-малко от 1/1000 от секундата по всяко време.   -  person Eric Lippert    schedule 28.01.2011
comment
@Eric, въпрос: DateTime.Now не Не изброявам 1/64 от секундата. Къде е документирано това?   -  person    schedule 28.01.2011
comment
@yodaj007: Също така. В него се казва, че при операционни системи NT3.5 и по-нови точността е приблизително 10 милисекунди или 1/100 от секундата. Приблизително означава не точно; на операционната система е позволено да реши каква е подходящата точност. Обикновено е близо до кванта на нишката по очевидни причини. На моята машина е с точност до 1/64 от секундата; вашата машина може да е по-добра или по-лоша.   -  person Eric Lippert    schedule 28.01.2011
comment
@Ерик: Разбрах. Изчислявах 1/64 = 0,015 секунди или 15,6 ms. Но не видях думата приблизително. Благодаря.   -  person    schedule 29.01.2011


Отговори (3)


Точно.

Но имате и друга възможност. Съхранявайте времето като брой тикове Int64 и използвайте InterlockedExchange за настройка. След това нишките могат да конструират свои собствени DateTime с помощта на конструктора Int64, което ви дава не спорове и без ключалки.

РЕДАКТИРАНЕ:

Като се има предвид, че предоставихте повече информация, сега е по-лесно да дадете пример.

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
person Moo-Juice    schedule 28.01.2011
comment
По-добре да използвате ToBinary/FromBinary, вместо просто да съхранявате необработените отметки, така че DateTimeKind също да се запази. (Въпреки че бих казал, че OP вероятно просто трябва да използва lock и обикновен DateTime, вместо да се опитва да бъде прекалено умен.) - person LukeH; 28.01.2011
comment
Въпреки че е възможно, и двете предложения звучат така, сякаш може да има много излишни реализации. Това, разбира се, зависи от това колко потребители има тази стойност на DateTime. - person Jens H; 28.01.2011
comment
@Sensai76, може би, но се съмнявам, че преобразуването ще бъде обезпокоително допълнително (въпреки че е трудно да се каже, без да се знае как това се използва от другите нишки), и като се има предвид това, ще бъде по-малко излишно, отколкото някакъв вид заключване . - person Moo-Juice; 28.01.2011
comment
Вие задавате стойността атомарно, но нищо не гарантира, че свойството Touched ще го прочете атомарно. - person Groo; 23.04.2014
comment
Мисля, че липсва нова ключова дума пред DateTime(Interlocked.Read(ref m_Touched)); - person Kenci; 03.08.2016

Вашият код не е безопасен за нишки, тъй като присвояването на DateTime не е гарантирано, че е атомарно. По принцип присвояванията на цели числа до 32 бита са атомни, но 64 не е необходимо да бъдат атомни.

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

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

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

person CodesInChaos    schedule 28.01.2011
comment
това е x64 приложение за x64 машини. има ли значение? Добра точка. - person vtortola; 28.01.2011
comment
@vtortola според това 64-битовите присвоявания могат да бъдат атомарни: CLI гарантира, че четенията и записите на променливи от типове стойности, които са с размер (или по-малък) от размера на естествения указател на процесора, са атомарни; ако изпълнявате C# код на 64-битова операционна система в 64-битова версия на CLR, тогава четенията и записите на 64-битови двойни и дълги цели числа също са гарантирани, че са атомарни. Езикът C# не гарантира това, но спецификацията за изпълнение го прави. stackoverflow.com/a/11745471/67824 - person Ohad Schneider; 28.11.2017

Това не е възможно - ще трябва да използвате lock или класа Monitor, за да синхронизирате достъпа до полето.

Това е така, защото DateTime е тип стойност - структура.

От MSDN - volatile (Справка за C#):

Ключовата дума volatile може да се приложи към полета от следните типове:

  • Референтни типове.
  • Типове указатели (в опасен контекст). Имайте предвид, че въпреки че самият указател може да бъде непостоянен, обектът, към който сочи, не може. С други думи, не можете да декларирате указател за volatile.
  • Типове като sbyte, byte, short, ushort, int, uint, char, float и bool.
  • Тип enum с един от следните основни типове: byte, sbyte, short, ushort, int или uint.
  • Параметри на общ тип, известни като референтни типове.
  • IntPtr и UIntPtr.

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

person Oded    schedule 28.01.2011