See, the dictionary itself is thread-safe for the case when you only have read operations from different threads. However, for the case when you still need initialization, it is necessary to take into account possible “races” between the initializing stream and the stream that reads the already initialized dictionary.
Consider this code:
var dict = Dictionary<K, V>(); dict[k1] = v1; // инициализация GlobalAccessibleDict = dict; // публикация
I read through the specification and did not find a clause that would prevent the compiler from rearranging initialization and publishing, because from the point of view of the publishing flow from rearranging these assignments, the meaning of the code does not change. Thus, from the point of view of another reading thread, initialization may occur too late . So, apparently, from the point of view of the language, this pattern is incorrect , and can lead to another thread reading the unde-initialized dictionary. In order to be sure, you must use lock (or, perhaps, publication through a volatile-field).
On the other hand, from the point of view of implementation in Microsoft .NET, the article Joe Duffy CLR 2.0 memory model states that in the implementation of .NET 2.0
Rule 2: It can move after one.
that is, permutations of records into variables are not allowed. If I correctly understood this text, it means that the race described by me is impossible, and initialization will end strictly before publication. Therefore, with a good degree of probability in the current implementation (and the .NET 4.0 memory model seems to be no weaker) everything is fine in your approach. (I did not find, however, anything about the order of updating data in other threads, so that the subtleties remain.)