1

Suppose I have the following class:

class Dummy
{
    public static Dictionary<int, int> dict = new Dictionary<int, int>();  // (1)

    static Dummy()   // (2)
    {
        dict.Add(1, 100);
        dict.Add(2, 200);
    }        
}

This type will be accessed by multiple threads. When will the (1) and (2) be executed? Will they be executed for each thread? Is it possible that a key duplication exception will occur?

smwikipedia
  • 61,609
  • 92
  • 309
  • 482
  • 2
    See: http://stackoverflow.com/a/7105/1336590 - "Static constructors are guaranteed to be run only once per application domain". And also: http://msdn.microsoft.com/library/aa645612.aspx – Corak Jul 07 '14 at 06:27
  • Not that I think it will change anything about the thread-safety (which I don't think is a problem), but you can write `public static Dictionary dict = new Dictionary { { 1, 100 }, { 2, 200 }, };` if you prefer. Then you don't need to write the static constructor by hand. (A static constructor will still be generated, so I guess the thread-issue is unchaged by this, so it is just a matter of which code you find more appealing.) – Jeppe Stig Nielsen Jul 07 '14 at 08:28

1 Answers1

3

Whenever the first instance is created, they will be accessed. No chance of key duplication. they will occur exactly once. And in case an error occurs during processing of static constructor, it will not be accessed again.

See JohnSaunders comments below as well for atomicity of this call.

Ehsan
  • 31,833
  • 6
  • 56
  • 65
  • 2
    They will occur exactly once, but not in an atomic manner. If two threads access the type, then it's possible that one of them could see a state in which `dict` only has a single entry, or for that matter, no entries. – John Saunders Jul 07 '14 at 06:28
  • @JohnSaunders agreed. – Ehsan Jul 07 '14 at 06:30
  • @JohnSaunders How to solve the atomic issue? Can I use the Lazy< T > initialization? – smwikipedia Jul 07 '14 at 06:51
  • @smwikipedia: I don't know offhand whether `Lazy` is atomic. You can solve your problem by adding `private static object _locker = new object();` then `static Dummy(){lock (_locker){dict.Add(1, 100);dict.Add(2,200);}`. You should also not use public fields. Use a property instead. – John Saunders Jul 07 '14 at 06:59
  • @JohnSaunders Are you claiming that one thread could access the static member of the class before the static constructor (running on another thread, say) has run to end? – Jeppe Stig Nielsen Jul 07 '14 at 08:25
  • @JeppeStigNielsen: Unless .NET supplies it's own lock, I don't see what would prevent that. – John Saunders Jul 07 '14 at 08:41
  • @JohnSaunders Then .NET must be supplying its own lock, for it works. I just tried to make a static constructor that takes a long time (contains a `Thread.Sleep` call, only after the sleep does it set some field). Then I started several threads to see if some of them could see my `static` field before the static constructor (which runs only in one of these threads, for sure) had finished. All threads got "blocked" waiting for the type initialization to have concluded. So the answer to smwikipedia's question seems to be: Yes, that is safe. – Jeppe Stig Nielsen Jul 07 '14 at 11:52
  • @JohnSaunders said: _They will occur exactly once, but not in an atomic manner. If two threads access the type, then it's possible that one of them could see a state in which dict only has a single entry, or for that matter, no entries._ That has turned out to be incorrect, see my comment above. – Jeppe Stig Nielsen Jul 07 '14 at 12:02
  • @JeppeStigNielsen: no, what you have proven is that, as of when you made the test, under the circumstances in which the test was performed, it was atomic. The next step would be to find documentation which _guarantees_ that it will be atomic under all circumstances and .NET releases. – John Saunders Jul 07 '14 at 14:59