12

I am Reading Joe's Albahari C# threading tutorial:

Author explains why DateTime.Now needs to be thread-safe:

Wrapping access to an object around a custom lock works only if all concurrent threads are aware of — and use — the lock. This may not be the case if the object is widely scoped. The worst case is with static members in a public type. For instance, imagine if the static property on the DateTime struct, DateTime.Now, was not thread-safe, and that two concurrent calls could result in garbled output or an exception. The only way to remedy this with external locking might be to lock the type itself — lock(typeof(DateTime)) — before calling DateTime.Now. This would work only if all programmers agreed to do this (which is unlikely). Furthermore, locking a type creates problems of its own.

For this reason, static members on the DateTime struct have been carefully programmed to be thread-safe.

According to MS docs, .NOW is public static DateTime Now { get; }, i.e. read-only property. Why bother with thread-safety, if it is read-only ? Two concurrent calls should be able to get the current time without interfering with each other ?

Edit: A lot of people, pointing out that questions is not very clear. I did make an assumption that it should be safe, because: it is read only and because it is time(always changing).

newprint
  • 6,936
  • 13
  • 67
  • 109
  • 3
    "Two concurrent calls should be able to get the current time without interfering with each other?" - yes, which means it's thread-safe. It's unclear what you're asking. Note that "read-only" doesn't automatically imply "thread-safe". Something that is publicly read-only may still change internal state. – Jon Skeet Oct 01 '14 at 15:06
  • 1
    It's a property. Accessing it runs some code. What code, isn't specified, it can be any code at all, so of course it can be not thread safe. –  Oct 01 '14 at 15:06
  • Just because a property is read-only doesn't mean that the code inside `get;` must be thread-safe; – Vlad Oct 01 '14 at 15:07
  • 2
    Additionally, consider that a property might be read-only, but access data which is mutated by another call - `List.Count` being an example. – Jon Skeet Oct 01 '14 at 15:08
  • 1
    I think you answered your own question. It needs to be thread safe because "Two concurrent calls should be able to get the current time without interfering with each other." If two concurrent calls interfered with each other (e.g., due to a race condition accessing cached time zone information), then it wouldn't be thread safe. – Raymond Chen Oct 01 '14 at 16:19

7 Answers7

9

Joseph is giving an example. It's not that Now needs to be thread-safe, all static methods need to be thread safe.

But, let's look at the all statics scenario. Statics need to be inherently thread-safe because if they have any state it is effectively global (and thus have a need to be thread-safe) and any caller to the method/property would be unable to make that data local and thus not need to worry about thread-safety. i.e. the caller would not be able to make it thread-safe reliably because no other code could possibly know how this code tried to make it thread safe and thus really can't be thread safe.

For example, let's say this fictitious DateTime.Now was implemented (poorly) like this:

private static long ticks;
public static DateTime Now
{
  get
  {
     ticks = UnsafeMethods.GetSystemTimeAsFileTime()
     return new DateTime(ticks); 
  }
}

...because ticks is long, it will not be atomic in 32-bit mode. Thus, the assignment to the shared ticks needs to be synchronized. Joseph is saying that you can't simply do this:

lock(somelock)
{
   var now = DateTime.Now;
}

...because any other code is free to do this:

var now = DateTime.Now;

...and thus your lock does nothing to make it thread-safe.

It's impossible for a consumer of a static method to ensure thread-safety of the call to the static, thus the onus is on the writer of the static to perform all the necessary steps to make it thread-safe.

Peter Ritchie
  • 35,463
  • 9
  • 80
  • 98
  • 1
    Incidentally, a design I see all too often in real-world hardware expects the time to be read with code equivalent to `UInt64 GetSysTime { CaptureTime(); return ((UInt64)GetCapturedMsb() << 32) | GetCapturedLsb();}. Having the hardware guarantee that the MSB and LSB are captured atomically doesn't help if they can't be read atomically with respect to capture. – supercat Oct 01 '14 at 21:58
  • 1
    A thread-safe approach is `UInt64 GetSysTime { UInt32 l1,l2,u; do { CaptureTime(); l1=GetCapturedLsb(); u=GetCapturedMsb(); l2=GetCapturedLsb(); } while (l1 != l2); return ((UInt64)u << 32) | l1; }` which would work just fine even if attempting to read a value during an increment could yield any arbitrary combination of old and new data. – supercat Oct 01 '14 at 22:01
  • 1
    It's not about making it thread safe, it's about the *need* to be thread safe :\ – Peter Ritchie Oct 01 '14 at 22:09
  • 1
    My point with the first example was to present a real-world situation where two threads both trying to read the time might stomp on each other even though reading the time should be something that multiple threads (or a main thread and an interrupt handler) should be able to to simultaneously without interference. – supercat Oct 01 '14 at 22:12
  • `...because ticks is long, it will not be atomic in 32-bit mode.` Wow, I had no idea that it works this way. Is it hardware implementation ? – newprint Oct 03 '14 at 14:02
  • 1
    RE long and atomic, yes. See http://stackoverflow.com/a/11745701/5620. In that question the related parts of the C# spec are quoted. – Peter Ritchie Oct 03 '14 at 14:08
  • 1
    FWIW a compliant CLI implementation *could* make long atomic on a 32-bit platform but it would have to do something more than a single CPU instruction (e.g. see http://www.plantation-productions.com/Webster/www.artofasm.com/Windows/HTML/AdvancedArithmetica2.html#1007619 for an example of how to multiply 64-bit values in 32-bit x86 assembly). – Peter Ritchie Oct 03 '14 at 14:12
  • @PeterRitchie Just came back to say that I found your answer to this question in another post, but you were ahead of me. Thanks ! – newprint Oct 03 '14 at 14:13
  • @newprint the other answer was just upvoted; but I couldn't tell *who*, so I referenced it here in case that was you :) – Peter Ritchie Oct 03 '14 at 14:15
5

Here's a Get that is not thread safe:

private string whyWouldYouDoThis;
public string NotThreadSafe
{
    get
    {
        whyWouldYouDoThis = "Foo";
        whyWouldYouDoThis += "Bar";
        return whyWouldYouDoThis;
    }
}

Thankfully the optimizer would probably see this and think "what..." and fix this for you, but as is, one thread could build "FooBar", be interrupted, the 2nd thread resets to "Foo" and now the first thread returns "Foo". Boom, race condition.

This is why even gets may require additional work to be thread-safe. Note the use of a private field? I'm willing to bet that this scenario was so common that it inspired the .Net's team policy of declaring all non-static methods and properties as non-thread safe by default. Special care was taken to make all static's thread-safe.

This is also an important reminder that multi-threading is hard, because most .Net languages don't make it obvious what is thread safe. Most of us think procedurally when we code, so it's not immediately apparent when we code a race condition. Use parallelism only if you have evidence you need it.

As Kamel BRAHIM points out, static and Get ("Read-only") does not guarantee thread safety. Immutability (the 'readonly' keyword) does, and this is true regardless of the type being returned, whether it's a string or a DateTime.

Guillaume CR
  • 3,006
  • 1
  • 19
  • 31
2

Being thread safe does not always require any synchronisation.

Eg.

public static int One {
  get {
    return 1;
  }
}

is thread safe without any special coding.

Remember the .NET coding guidelines: static members should be thread safe (ie. unless documented otherwise), so this is the default position. But this guideline says nothing about any steps necessary to achieve that: it can be zero effort.

A read only property that cached the current value (maybe it is expensive to determine, but doesn't change much) may need to synchronise the cache, perhaps using a Monitor, but how thread safety is achieved is an implementation detail.

Edit To address the comment "doesn't address the question": because otherwise – DateTime.Now is not thread safe – every program would need to provide its own synchronisation around every call to DateTime.Now. (I considered the underlying question to be "the guideline says I should do X, but X is implicit, what should I do?" to which the answer is: "if you get compliance for free, then accept it".)

Richard
  • 106,783
  • 21
  • 203
  • 265
2

Each call to DateTime.Now needs to actually get the current time from some common mutable resource (the current time is changing after all; it's not like its constant). Accessing a common mutable resource from multiple threads means you need to be sure that you do so in a safe manner.

GregC
  • 7,737
  • 2
  • 53
  • 67
Servy
  • 202,030
  • 26
  • 332
  • 449
  • 1
    That argument doesn't seem quite right. It's unlikely that the implementation of `DateTime.Now` manages that mutable resource (i.e. the current time) *itself*. More likely, `DateTime.Now` is simply a consumer of that resource. It reads the current time from somewhere else (e.g. via a system / Windows API call) and forwards it to its own caller. The tricky part is then not that `DateTime.Now` must be thread-safe (because that should be fairly trivial due to its mostly-only-forwarding nature), but that whatever component that *does* directly manage the mutable resource is. – stakx - no longer contributing Oct 01 '14 at 15:54
  • That being said, I do *not* dispute the fact that `DateTime.Now` must also be thread-safe. – stakx - no longer contributing Oct 01 '14 at 15:58
  • @stakx sure, and that is in fact the case, but that's opening up the black box, as it were. The quote in the question is discussing `DateTime` as a black box, which means ensuring that what `DateTime` exposes is thread safe. The fact that the synchronization needed to perform the operations it performs is done in other dependent resources rather than in the `DateTime` class itself is going beyond the scope of the question. It's important that `DateTime` expose an API that is safe to be used from multiple threads, that's what the quote is asserting. – Servy Oct 01 '14 at 15:58
  • You already opened that black box in your answer by explaining what `DateTime.Now` needs to do internally, which is perhaps what nagged me about it in the first place. But I agree with what you're saying; I might have misunderstood the point your answer is trying to drive home. The last sentence of your last comment makes that much clearer, IMHO. – stakx - no longer contributing Oct 01 '14 at 16:03
  • 1
    @stakx My answer is referring to the fact that conceptually, in order to accomplish the task of returning an object represeting the current time, something, somewhere, is going to need to keep track of the current time, meaning it'll be mutating, and it'll be accessed from multiple threads. Whether that code is in the `DateTime` class or refactored out to other dependencies isn't important to us as external users of `DateTime`. What's important is that someone, somewhere, needs to do that operation, and they need to ensure proper synchronization when they do. – Servy Oct 01 '14 at 16:07
2

Imagine if Now is implemented like:

public static DateTime Now { get { return internalToday + internalCurrentTime; } }

and we are not declaring it thread safe - meaning "this method will work correctly only when used in single threaded environment".

So if you use such method from multiple threads it is possible to get results like "Yesterday 0:01AM", "Today 0:01" and "Today 11:59PM" for exactly the same moment of time because method combines 2 values in non-thread safe way (even if each is thread safe on its own).

So to let you use such value in thread safe way authors of the library must take care of computing value in thread safe way (i.e. lock around).

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
0

Date.Now is thread safe because each time you need to get a value from the property a new DateTime is created, and given that all properties are created in the constructor and all properties are only get make it thread safe. Simply speaking it's immutable

DateTime.Now look like this

[__DynamicallyInvokable]
    public static DateTime Now
    {
      [__DynamicallyInvokable] get
      {
        DateTime utcNow = DateTime.UtcNow;
        bool isAmbiguousLocalDst = false;
        long ticks1 = TimeZoneInfo.GetDateTimeNowUtcOffsetFromUtc(utcNow, out isAmbiguousLocalDst).Ticks;
        long ticks2 = utcNow.Ticks + ticks1;
        if (ticks2 > 3155378975999999999L)
          return new DateTime(3155378975999999999L, DateTimeKind.Local);
        if (ticks2 < 0L)
          return new DateTime(0L, DateTimeKind.Local);
        else
          return new DateTime(ticks2, DateTimeKind.Local, isAmbiguousLocalDst);
      }
    }
BRAHIM Kamel
  • 13,492
  • 1
  • 36
  • 47
  • 2
    This is not relevant to the question. The question is asking about why the implementation of `Now` needs to go out of its way to ensure that it is thread safe. It's not even an instance member and as such the fact that `DateTime` is immutable once created is irrelevant. The act of creating one in this context requires work to ensure it is safe. – Servy Oct 01 '14 at 15:15
  • @Servy does require access to a common mutable resource can u be more explicit on this point please speaking in general does not make sense you have edited your comment many times – BRAHIM Kamel Oct 01 '14 at 15:19
  • I edited the comment once, not many times. How do you expect `Now` to know what the current time is? Clearly there needs to be a clock somewhere that keeps track of the current time. It is going to be a common mutable resource accessible to multiple threads. – Servy Oct 01 '14 at 15:24
  • I know that somewhere there is a clock :) but this does not mean that can violate thread safety – BRAHIM Kamel Oct 01 '14 at 15:27
  • 1
    This in combination with Guillaume's response seems to be the answer, no? – George Mauer Oct 01 '14 at 15:29
  • @KamelBRAHIM It means you need to make sure that it doesn't. It won't just work by default without consideration. – Servy Oct 01 '14 at 15:35
  • @GeorgeMauer What makes it the answer? The fact that a `DateTime` instance is immutable once created has nothing to do with the fact that synchronization is important when actually constructing those immutable instances. – Servy Oct 01 '14 at 15:35
  • I agree with Servy, you've simply concentrated on the implementation of `Now` and ignored the *why*. – Peter Ritchie Oct 01 '14 at 20:49
0

What does MSDN actually flag as a problem? DateTime.Now property is implemented in such a way that it depends on "global" state: Have a look at TimeZoneInfo.s_cachedData, it's accessed from GetDateTimeNowUtcOffsetFromUtc().

Here's how it can get you into trouble After one CPU core changes the static value in response to a system event of time zone change, a stale cache line on another core would be accessed by DateTime.Now and would produce an incorrect time value, potentially differering by hours from the expected value since the static access is not protected by a sync object.

To fix things you could rely on DateTime.UtcNow, and figure out time zone information as a separate exercise, then smash them together. However, I fear that for the most frequently-used case, this would be overkill. Time zone offsets just don't change that often, (for example, only twice a year where I live).

Comparison with other languages: The signature of the property does not declare that there is a side-effect that can affect correctness of the returned result. In Haskell, for example, they would return an IO monad of DateTime, instead of DateTime. As another insight, look at the way hardware registers are commonly accessed in C++ by using keyword volatile. The keyword ensures the cache lines in the CPU that store the value are correctly refreshed on each access.

GregC
  • 7,737
  • 2
  • 53
  • 67
  • This is not true. The `DateTime` instance *isn't* cached. It's re-computed on each call to `Now`. – Servy Oct 01 '14 at 15:18
  • If you're referring to the current timezone then yes. That's not clear from your answer. – Servy Oct 01 '14 at 15:26
  • 2
    The fact that it's not obvious at first why time zone stuff would be relevant is exactly why your answer would have benefited greatly from mentioning that instead of being nebulous. – Servy Oct 01 '14 at 15:34
  • Rather than talking about the name of the variable that's cached, the answer would be better off explaining conceptually what is cached and why (in addition to the code, if you want) since clearly the question is expressing confusion as to what would need to be stored globally in the first place. – Servy Oct 01 '14 at 15:53
  • @Servy I've edited my response in light of your comments. Let's clean up comments to make it easier on future readers – GregC Oct 01 '14 at 20:17
  • I think you're in the weeds to much, explaining what DateTime.Now does, it distracts away from the the real question of why statics need to be thread-safe – Peter Ritchie Oct 01 '14 at 20:47
  • @PeterRitchie I like your answer (and up-voted), but I am trying to bring aspects that are overlooked in other answers. – GregC Oct 02 '14 at 15:07
  • DateTime.Now is simply an example that Joseph used as a metaphor for the concept. If he didn't use DateTime.Now how would you answer apply? – Peter Ritchie Oct 02 '14 at 15:41