Безопасен ли е Stopwatch.ElapsedTicks?

Ако имам споделен System.Diagnostics.Stopwatch екземпляр, могат ли множество нишки да извикат shared.ElapsedTicks по безопасен начин и да получат точни резултати?

Има ли някаква разлика по отношение на безопасността/точността на нишките между използването на споделен екземпляр на Хронометър по този начин и използването на статичния метод GetTimeStamp()?

Измервам интервали от около 180 ms и откривам, че използването на споделения екземпляр ми дава по-голямо разпространение на резултатите, включително значителен брой, които са по-кратки, отколкото бих очаквал.

Машината има множество процесори (2 * Intel X5550 за това, което си струва)


person Rob    schedule 12.07.2011    source източник
comment
Само за пояснение - не питам дали трябва да споделям членове на екземпляра на хронометъра в множество нишки - това става ясно от връзката, предоставена от Магнус. Опитвам се да разбера/обясня неочакваното поведение на съществуващия код и се чудех дали споделен екземпляр на Хронометър може да е проблемът.   -  person Rob    schedule 12.07.2011
comment
Свързано възможно внедряване: stackoverflow.com/questions/37799650/simple-lockless-stopwatch   -  person Jason C    schedule 27.05.2021


Отговори (4)


От MSDN:

Не се гарантира, че членовете на екземпляра са безопасни за нишки.

person Magnus    schedule 12.07.2011
comment
+1, отговорът ви е правилен.. добавете към него, че Stopwatch.GetTimestamp(); е безопасен за нишки, защото е статичен. - person Jalal Said; 12.07.2011
comment
Имаше информация за безопасност на нишките в документацията на MSDN. Но явно е премахнат. Също така прегледът на кода и емпиричното тестване изглежда предполагат, че свойствата ElapsedXXX са безопасни за нишки, както се предполага от по-нови отговори. - person blaz; 15.04.2020

Разглеждайки изходния код, това е безопасен за нишки, но не трябва да използвате: Stop(), Reset() и Restart().

Така че, ако стартирате споделен екземпляр, не го модифицирате и извиквате само ElapsedXXX свойства, трябва да сте добре.

person xmedeko    schedule 11.04.2019
comment
@apdevelop Не, ElapsedXXX не са атомарни, затова не трябва да използвате Stop(), Reset(), Restart() от друга нишка. Просто погледнете изходния код. - person xmedeko; 17.10.2019
comment
Имах предвид създаване на Stopwatch и извикване на неговите Start/Stop методи в една нишка и след това извикване на ElapsedXXX методи от друга нишка(и). Атомично четене, свързано с работа с Int64 полета от различни нишки, когато трябва да използваме методи от Interlocked клас. В случай на четене на свойството ElapsedMilliseconds това не е възможно. - person apdevelop; 18.10.2019
comment
Емпиричният тест на 64-битова машина с .NET 4.8 изглежда потвърждава безопасността на нишката на свойствата ElapsedXXX. - person blaz; 15.04.2020
comment
Въпреки че това свойство е безопасно за реклами, стига да не извиквате методите Start(), Reset() или Stop(), важно е да се отбележи, че ако използвате отметките за аритметика и след това предавате стойността в TimeSpan конструктор, например, един stopWatch.ElapsedTicks Тикът не е еквивалентен на TimeSpan тикове, както е описано тук: geekswithblogs.net/BlackRabbitCoder/archive/2012/01/12/. За да получите еквивалентни отметки, бихте искали да използвате stopWatch.Elapsed.Ticks. - person Robin Lashof-Regas; 30.06.2020

Гледайки изходния код, той не е безопасен за нишки.

person SLaks    schedule 12.07.2011
comment
Можете ли да заключите какви неточности могат да възникнат? Питам, защото въпреки че виждам неочаквани резултати, те не са невъзможни - не получавам никакви отрицателни измервания или резултати, които са от порядъка на величината. Дори след милиони измервания. - person Rob; 12.07.2011
comment
На 32-битови машини е уязвим за разкъсване, ако бъде извикан, докато извиквате Start() или Stop(). (може да прочете полето long elapsed, докато се записва в него). На x64 изглежда безопасно. - person SLaks; 12.07.2011
comment
Методът ElapsedTicks модифицира ли основния екземпляр по някакъв начин, който би накарал множество нишки, използващи този метод, да се намесват една в друга, ако няма такива извиквания, които са едновременни с други методи като Start, Stop и т.н.? Не бих си помислил, че ElapsedTicks изобщо ще трябва да променя членове на екземпляр. - person supercat; 11.08.2015

Можете да използвате https://msdn.microsoft.com/en-us/library/dd642243(v=vs.110).aspx

ThreadLocal<T> 

като този:

    ThreadLocal<Random> _localRandom = new ThreadLocal<Random>(() => new Random());
    ThreadLocal<Stopwatch> _localStopwatch = new ThreadLocal<Stopwatch>(() => new Stopwatch());

    public void SomeTest()
    {
        Action someAction = () =>
            {
                _localStopwatch.Value.Reset();
                _localStopwatch.Value.Start();
                Thread.Sleep(_localRandom.Value.Next(100, 500));
                _localStopwatch.Value.Stop();
                Debug.Print(_localStopwatch.Value.Elapsed.TotalMilliseconds.ToString(CultureInfo.InvariantCulture));
            };

        var actions = Enumerable.Range(0, 1000).Select(i => someAction).ToArray();
        Parallel.Invoke(new ParallelOptions {MaxDegreeOfParallelism = Environment.ProcessorCount}, actions);
    }
person Denis    schedule 16.01.2014
comment
Този отговор не е за безопасността на нишката на Хронометъра. Става въпрос за това как да се предостави отделен екземпляр на Хронометър за всяка нишка. - person blaz; 15.04.2020
comment
Това изглежда ужасно заплетено, защо да използвате ThreadLocal<Stopwatch>, когато можете просто да декларирате локална променлива в нишката? - person Liam; 07.08.2020
comment
@Liam, да, можете да използвате атрибута ThreadStatic, но имайте предвид, че инициализаторът по подразбиране ще извика само веднъж за всички нишки, а не по една за всяка нишка. Така че предпочитам да използвам ThreadLocal навсякъде - person Denis; 18.08.2020