Question

It strikes me as an odd design choice that the current culture information (CurrentCulture and/or CurrentUICulture) is a a property of the running thread. At the very least it seems like the scope of such a thing should be one level up, at the process level.

But these things usually make sense once you hear the rationale. It might be enlightening to find out why the .NET designers decided that Thread was the right place to put this property.

Was it helpful?

Solution

For starters, it wasn't really their choice. That decision was made a long time before they got started, culture is a property of an operating system thread. Review the SDK docs for the Get/SetThreadLocale() API functions for example.

That doesn't completely explain it, they have virtualized other OS features, albeit that this one is very hard to virtualize because so many APIs are culture sensitive, especially COM ones.

The next good reason is because changing the culture process-wide is so extremely difficult to implement. It is an unsolvable race condition. Some other thread might well be in the middle of formatting data that has culture affinity. While a lock would work to prevent it from using culture properties just as it is changing, it can not prevent it from changing in the middle of a chain of formatting calls. It would require them to take some kind of global lock and hold it for the duration of the formatting job. Deadlock is very likely.

There's another aspect to this, one that I think is the real problem. It is related to the Thread.ExecutionContext property. The framework uses this to "flow" thread state from one thread to another. Very obscure but important to imbue things like the security context onto a worker thread. It would have been ideal if that context could also imbue the culture so that you can be sure that any of the workers you start have the same culture you selected and not the operating system default.

It doesn't, I don't really know why. Probably because the very first reason I gave. That does however make it very perilous to change a thread's culture. The kind of bugs that can cause are very subtle. Like creating a SortedDictionary with a string as the key in your main thread with a non-operating system default culture. Then finding out that a worker thread can't occasionally find stuff back anymore because the string sorting rules are different.


EDIT: there's some relief from this problem in .NET 4.5, it supports the new static CultureInfo.DefaultThreadCurrentCulture and DefaultThreadCurrentUICulture properties.


EDIT2: culture now flows as described in the 4th paragraph in .NET 4.6. This should alleviate all concerns.

OTHER TIPS

I'll take a shot - maybe because you would need multiple simultaneous thread using different culture? If you think of a multilingual asp.net website, you don't want the process to be tied to one language... a web request could be EN-US and another fr-FR.

Window handles are themselves thread specific. You should never use a window handle (for a top level window, child control etc) in the context of a different thread because the code that implements window handling (GDI) is not itself thread safe. As the UICulture is window specific it means it also becomes defined at the thread level.

Other GUI aspects are also thread specific, such as the active window and the focus. Although there is an API, I cannot remember the name, that joins the UI context from different threads together so that the focus, active window is shared between multiple user interface threads.

The CurrentCulture is nothing but a reference to a CultureInfo, so not much would be lost by allowing it to hang on the thread (just the memory for one reference). At the same time, you gain the possibility to allow users to finely control the current culture per thread - which turns out to be important in some kinds of applications.

One reason for having it this fine grained might be more obvious for non-English speaking users of modern software. I for one have to regularly switch the keyboard in Windows and am able to do that easily with one global keyboard shortcut. Having the CultureInfo on the thread allows us to easily implement similar logic in our .NET apps without having to change that info per process.

Usage examples that come to mind:

  1. I might want a shortcut that would change the culture in my program for a short period of time on request for the current user (many applications need to allow several users on the same workstation and in the same session). But that same process might have to continue using the default CultureInfo on the machine to e.g. log with always the same timestamp format.

  2. You might also have a report solution that would dump out reports for several branches of a global company, each in their own culture. Your design would be less constrained if you could change the CultureInfo per thread.

  3. Another reason would be if you would want to write to a file using a particular culture, but you wouldn't want to specify the culture in your write functions (e.g. because those functions have already been written). Then you're able to change that logic easily without changing it on other threads which may be doing work that needs the default culture.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top