1

Preface: I know how to create a read-only CultureInfo object. That is not the question and it has been answered in detail here:

Note that the text of that question is similar to this one, but the answers are completely different. Before thinking about closing this question as a duplicate of the other one, please consider the fact that none of the answers in the other question answers this question.


My question:

Is it thread-safe to access instance members of a read-only CultureInfo object?

Reasons to assume that it is:

  • If it weren't, using instance members of CultureInfo.InvariantCulture or objects retrieved by CultureInfo.GetCultureInfo wouldn't be thread-safe, and a lot of code would break.

  • The community seems to think so (see Henk's comment on this answer), but does not explain why.

Reasons to assume that it isn't:

Community
  • 1
  • 1
Heinzi
  • 167,459
  • 57
  • 363
  • 519
  • The documentation pages always include a note about [thread safety](https://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo(v=vs.110).aspx#Anchor_8) near the end. Did you check it? Besides, thread-safety is a concern only when modifying an object. It isn't a concern with read-only objects or when the only access is for reading – Panagiotis Kanavos Apr 21 '16 at 10:21
  • *Why* are you asking this question? Did you encounter a problem? As for MSDN, it *does* state that static members are thread safe. `InvariantCulture` *is* a static, as is `GetCultureInfo()`. – Panagiotis Kanavos Apr 21 '16 at 10:25
  • Finally, if you want a better explanation, just [check the source code](http://referencesource.microsoft.com/#mscorlib/system/globalization/cultureinfo.cs) – Panagiotis Kanavos Apr 21 '16 at 10:26
  • @PanagiotisKanavos: Yes, I checked it, it contains just the default disclaimer. I've clarified that in the question. I know that *getting* InvariantCulture is static, but *accessing* `InvariantCulture.Calendar`, for example, is a *member access*, and, thus, not guaranteed to be thread-safe. – Heinzi Apr 21 '16 at 12:39
  • Unless it's only for reading. Given that the source *is* available you can check it directly, but simply returning a value from a backing field *is* thread safe – Panagiotis Kanavos Apr 21 '16 at 13:29
  • @PanagiotisKanavos: True, but implementations might change. That's why "design by contract" exists. :-) – Heinzi Apr 21 '16 at 13:41
  • Yes, and in this case *reading* isn't supposed to change anything. In fact, you *could* argue that any field access method is not thread safe even if the code actually is, because someone may change it in the future to regenerate the field or something. – Panagiotis Kanavos Apr 21 '16 at 14:22
  • On the other hand, with open source code, the code *is* the contract. – Panagiotis Kanavos Apr 21 '16 at 14:22
  • @PanagiotisKanavos: If you plan to never upgrade your libraries, sure. ;-) On a more serious note: I actually don't think closed/open source makes a difference here; design by contract is about the *division of responsibility* between user and library. If a method's contract states that it returns a list of user names (and nothing else), the library developer has the freedom to return them in a different order in the next version without telling anyone. If he decides to return a list of user objects instead, he breaks the contract and must declare this as a breaking change. – Heinzi Apr 21 '16 at 14:29

1 Answers1

2

Thread safety is an issue when you are altering an object, so the question is: are you altering the object or does something happen inside the CultureInfo that could change its state.

MSDN isn't particularly clear about this: it just shows the default notice about thread-safety.

So we have to find out ourselves. Luckily, the CultureInfo class is made available through the reference source. There you will find it will load the culture data at the start of the method, and cache that result inside the CultureInfo class.

The initialization of properties is not thread-safe. See for example the NumberFormat property: it can instantiate two instances due to concurrent calls. There is no locking!

There are more problems at some places, for example the NumberFormat property again, where you can change its properties. Inside that class it checks if it is writable or not, so if you are using default cultures (the read-only ones, like InvariantCulture) there is no thread-safety issue. In all other cases we can't assume it is thread-safe.

Conclusion: they are not thread-safe.

Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
  • But it should be threadsafe, otherwise as the OP points out, you could never safely use `CultureInfo.InvariantCulture` since there is only one instance of it, and you'd never know if another thread (perhaps in an entirely separate class library) was using it. I suppose Microsoft could have made an egregious error with `CultureInfo.InvariantCulture`, but I'm pretty sure they didn't, and accessing it is indeed threadsafe. – Matthew Watson Apr 21 '16 at 10:39
  • But that one is safe since you can't change its state. Its backing data is read-only. If you create your own `CultureInfo`, you could end up in trouble with multi-threading and lazy loading of `NumberFormat` for example. @MatthewWatson – Patrick Hofman Apr 21 '16 at 10:41
  • Ah I see, your conclusion is talking about non-read-only CultureInfo. I was confused because the OP was asking only about read-only ones. To be clear, is your answer to the question "Is it thread-safe to access instance members of a read-only CultureInfo object?" `Yes`? – Matthew Watson Apr 21 '16 at 10:42
  • You could end up with two `NumberFormat` instances, but since they are read-only internally, there isn't an issue. – Patrick Hofman Apr 21 '16 at 10:43
  • @MatthewWatson for your edited comment: basically yes, but not entirely since there could still be two instances of the same backing info. – Patrick Hofman Apr 21 '16 at 10:44
  • @PatrickHofman NumberFormat probably *is* thread-safe for read-only CultureInfo objects.. The only modification is assigning a fully initialized object to the backing field. Even if this happens *twice*, the two objects will be identical as long as they are generated from the same m_CultureData field – Panagiotis Kanavos Apr 21 '16 at 14:26
  • They have the same fields but they are not identical. Comparing for equality is one thing that goes wrong @pan – Patrick Hofman Apr 21 '16 at 16:03