16

I've been using this pattern to initialize static data in my classes. It looks thread safe to me, but I know how subtle threading problems can be. Here's the code:

public class MyClass // bad code, do not use
{
    static string _myResource = "";
    static volatile bool _init = false;
    public MyClass()
    {
        if (_init == true) return;
        lock (_myResource)
        {
            if (_init == true) return;
            Thread.Sleep(3000); // some operation that takes a long time 
            _myResource = "Hello World";
            _init = true;
        }
    }
    public string MyResource { get { return _myResource; } }
}

Are there any holes here? Maybe there is a simpler way to do this.

UPDATE: Consensus seems to be that a static constructor is the way to go. I came up with the following version using a static constructor.

public class MyClass
{
    static MyClass() // a static constructor
    {
        Thread.Sleep(3000); // some operation that takes a long time 
        _myResource = "Hello World";
    }

    static string _myResource = null;

    public MyClass() { LocalString = "Act locally"; } // an instance constructor

    // use but don't modify
    public bool MyResourceReady { get { return _myResource != null; } }
    public string LocalString { get; set; }
}

I hope this is better.

RaoulRubin
  • 518
  • 2
  • 6
  • 18
  • @RaoulRobin, a static constructor would be in order, but only if you want a static class. If you don't want to share your fields in all MyClass instances, then you must employ proper synchronization. – Kiril Jun 04 '10 at 03:50
  • In the real-life version the static resource is Dictionary<> that gets preloaded, than read concurrently in multiple instances of the class. MSDN says concurrent reads are OK as long as the Dictionary is not being modified during the reads. Thanks for the comment. – RaoulRubin Jun 04 '10 at 04:09

5 Answers5

14

You can use static constructors to intialize your static variables, which C# guarantees will only be called once within each AppDomain. Not sure if you considered them.

So you can read this: http://msdn.microsoft.com/en-us/library/aa645612(VS.71).aspx (Static Constructors)

And this: Is the C# static constructor thread safe?

Community
  • 1
  • 1
6

Performing a lock() on _myResource and changing it inside lock() statement seems like a bad idea. Consider following workflow:

  1. thread 1 calls MyClass().
  2. execution stops before line _init = true; right after assigning _myResource.
  3. processor switches to thread 2.
  4. thread 2 calls MyClass(). Since _init is still false and refrence _myResource changed, it succesfully enters lock() statement block.
  5. _init is still false, so thread 2 reassigns _myResource.

Workaround: create a static object and lock on this object instead of initialized resource:

private static readonly object _resourceLock = new object();

/*...*/

lock(_resourceLock)
{
    /*...*/
}
max
  • 33,369
  • 7
  • 73
  • 84
  • Good point. I don't really understand the sequence of execution that take place during construction. I see the problem. I think there may also be a problem with assigning a new value to the string. E.G. _myResource = "Some New Value"; – RaoulRubin Jun 04 '10 at 03:40
  • One more thing to remember: string constants are interned by default (that is, `object.RefererecnceEquals(s1, s2)` will return true for equal string constants s1 and s2), so it's possible to do things like lock("MyString"), but this design is not recommended by MS. That's why using string variable as an argument in `lock()` statement can lead to some unexpected results. – max Jun 04 '10 at 04:14
3

Your class is not safe:

  1. You change the object you're locking on after you've locked on it.
  2. You have a property that gets the resource without locking it.
  3. You lock on a primitive type, which is generally not a good practice.

This should do it for you:

public class MyClass
{
    static readonly object _sync = new object();
    static string _myResource = "";
    static volatile bool _init = false;

    public MyClass()
    {
        if (_init == true) return;
        lock (_sync)
        {
            if (_init == true) return;
            Thread.Sleep(3000); // some operation that takes a long time 
            _myResource = "Hello World";
            _init = true;
        }
    }

    public string MyResource 
    { 
        get 
        { 
            MyClass ret; // Correct
            lock(_sync)
            {
                ret = _myResource;
            }
            return ret;
        } 
    }
}

Update:
Correct, the static resource should not be returned directly... I've corrected my example accordingly.

Kiril
  • 39,672
  • 31
  • 167
  • 226
  • You make a great point. Locking on _myResource was a bad idea. I think there was also a bigger problem - the getter was returning a reference to the static resource. In your example I don't think the get{ lock(_sync) fixes this. Perhaps a better solution would have been to lock, then make a copy and return it. Thanks. – RaoulRubin Jun 04 '10 at 03:59
  • String is not a primitive type, but it is still a bad idea to lock on it since if it is interned, your lock object can be exposed outside of the class. – Matt H Jun 04 '10 at 05:41
  • @Matt, according to msdn a string is a primitive: http://msdn.microsoft.com/en-us/library/ms228360%28VS.80%29.aspx – Kiril Jun 04 '10 at 09:16
  • Huh, I guess I was confusing primitive with built-in value type. – Matt H Jun 04 '10 at 20:44
  • @Matt, In C++ a string is not a primitive type, but in C# and Java it is. A primitive type can be "a built-in type" which "is a data type for which the programming language provides built-in support." http://en.wikipedia.org/wiki/Primitive_data_type – Kiril Jun 04 '10 at 21:01
  • @Lirik: It seems that the documentation and the language don't completely agree, though. http://msdn.microsoft.com/en-us/library/system.type.isprimitive.aspx, and typeof(string).IsPrimitive returns false. – Matt H Jun 04 '10 at 23:00
  • @Matt Yah, there is some discrepancy there... there is another msdn article that defines primitives as: Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double, and Single. – Kiril Jun 04 '10 at 23:33
2

Depending on your use case (i.e. if threads don't need to pass information to each other using this variable), marking the member variable as [ThreadStatic] may be a solution.
See here.

goric
  • 11,491
  • 7
  • 53
  • 69
0
static string _myResource = "";
...
public MyClass()
{
    ...
    lock (_myResource)
    {
    }
}

Due to string interning, you should not lock on a string literal. If you lock on a string literal and that string literal is used by multiple classes then you may be sharing that lock. This can potentially cause unexpected behavior.

Randy Levy
  • 22,566
  • 4
  • 68
  • 94
  • 1
    FYI I had to look up interning. Here's the MSDN: The common language runtime conserves string storage by maintaining a table, called the intern pool, that contains a single reference to each unique literal string declared or created programmatically in your program. Consequently, an instance of a literal string with a particular value only exists once in the system. – RaoulRubin Jun 04 '10 at 04:22
  • To the downvoter, I wouldn't mind a comment. The question is what are the holes in the code (from a thread safety point of view). I posted one hole the poster was performing -- locking on string constants. Perhaps you thought the posted code was a recommendation? – Randy Levy Sep 01 '12 at 03:18