Is Stopwatch.ElapsedTicks threadsafe?
Asked Answered
K

4

16

If I have a shared System.Diagnostics.Stopwatch instance, can multiple threads call shared.ElapsedTicks in a safe manner and get accurate results?

Is there any difference in terms of thread-safety/accuracy between using a shared instance of Stopwatch in this way, and using the static GetTimeStamp() method?

I'm measuring intervals of around 180ms, and finding that using the shared instance is giving me a larger spread of results, including a significant number that are shorter than I would expect.

The machine has multiple CPUs (2 * Intel X5550 for what it's worth)

Koto answered 12/7, 2011 at 13:0 Comment(2)
Just to clarify - I'm not asking whether I should share stopwatch instance members across multiple threads - that's clear from the link Magnus provided. I'm trying to understand/explain the unexpected behaviour of existing code, and wondered if a shared Stopwatch instance could be the problem.Koto
Related possible implementation: https://mcmap.net/q/66687/-simple-lockless-stopwatchDemello
C
16

From MSDN:

Any instance members are not guaranteed to be thread safe.

Corsica answered 12/7, 2011 at 13:2 Comment(3)
+1, your answer is right.. add to it that Stopwatch.GetTimestamp(); is thread safe because it is static.Cathcart
There used to be thread-safety information in MSDN documentation. But has apparently been removed. Also code review and empirical testing seems to suggest that ElapsedXXX properties are thread safe as suggested by more recent answers.Eisele
@JalalSaid while that method should be threadsafe, would it give accurate results if you first call it on one thread and then a diffrent one and then subtract them to get the elapsed time?Gensler
H
10

Looking at the source code, it is thread-safe, but you must not use: Stop(), Reset() and Restart().

So, if you start a shared instance, does not modify it and call only ElapsedXXX properties, you should be fine.

Hyps answered 11/4, 2019 at 9:9 Comment(4)
@apdevelop No, ElapsedXXX are not atomic, that's why you must not use Stop(), Reset(), Restart() from other thread. Just look at the source code.Hyps
I meant creating Stopwatch and calling its Start/Stop methods in one thread and then calling ElapsedXXX methods from another thread(s). Atomic reading related to dealing with Int64 fields from different threads, when we should use methods from Interlocked class. In case of reading ElapsedMilliseconds property it's not possible.Blindheim
Empirical test on 64-bit machine with .NET 4.8 seems to confirm thread-safety of ElapsedXXX properties.Eisele
While this property is theadsafe as long as you do not call the Start(), Reset(), or Stop() methods, it is important to note that if you are using the ticks for arithmetic and then passing the value into a TimeSpan constructor, for example, one stopWatch.ElapsedTicks Tick is not equivalent to TimeSpan Ticks as described here: geekswithblogs.net/BlackRabbitCoder/archive/2012/01/12/…. To get equivalent ticks you would want to use stopWatch.Elapsed.Ticks.Stertor
C
5

Looking at the source code, it is not thread-safe.

Codi answered 12/7, 2011 at 13:7 Comment(3)
Are you able to infer what inaccuracies might occur? I ask because although I'm seeing unexpected results, they are not "impossible" ones - I'm not getting any negative measurements, or results that are orders of magnitude out. Even after millions of measurements.Koto
On 32-bit machines, it's vulnerable to tearing if called while calling Start() or Stop(). (it might read the long elapsed field while it's being written to). On x64, it looks safe.Codi
Does the ElapsedTicks method modify the underlying instance in any fashion that would cause multiple threads using that method to interfere with each other, if no such calls are simultaneous with other methods like Start, Stop, etc.? I wouldn't think ElapsedTicks would need to modify any instance members at all.Malka
R
4

You can use https://msdn.microsoft.com/en-us/library/dd642243(v=vs.110).aspx

ThreadLocal<T> 

like this:

    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);
    }
Requite answered 16/1, 2014 at 11:35 Comment(3)
This answer is not about Stopwatch thread-safety. It is about how to provide separate Stopwatch instance to each thread.Eisele
This seems awfully convoluted, why use ThreadLocal<Stopwatch> when you can just declare a local variable inside the thread?Woolworth
@Liam, yes, you can use the ThreadStatic attribute, but keep in mind that the default initializer will only call once for all threads, not one for each thread. So, I prefer to use ThreadLocal everywhereRequite

© 2022 - 2025 — McMap. All rights reserved.