Note that there are some explanatory texts on larger screens.

plurals
  1. POIs a lock required with a lazy initialization on a deeply immutable type?
    text
    copied!<p>If I have a deeply immutable type (all members are readonly and if they are reference type members, then they also refer to objects that are deeply immutable).</p> <p>I would like to implement a lazy initialized property on the type, like this:</p> <pre><code>private ReadOnlyCollection&lt;SomeImmutableType&gt; m_PropName = null; public ReadOnlyCollection&lt;SomeImmutableType&gt; PropName { get { if(null == m_PropName) { ReadOnlyCollection&lt;SomeImmutableType&gt; temp = /* do lazy init */; m_PropName = temp; } return m_PropName; } } </code></pre> <p>From what I can tell: </p> <pre><code>m_PropName = temp; </code></pre> <p>...is threadsafe. I'm not worried too much about two threads both racing to initialize at the same time, because it will be rare, both results would be identical from a logical perspective, and I'd rather not use a lock if I don't have to.</p> <p>Will this work? What are the pros and cons?</p> <p><strong>Edit:</strong> Thanks for your answers. I will probably move forward with using a lock. However, I'm surprised nobody brought up the possibility of the compiler realizing that the temp variable is unnecessary, and just assigning straight to m_PropName. If that were the case, then a reading thread could possibly read an object that hasn't finished being constructed. Does the compiler prevent such a situation?</p> <p>(Answers seem to indicate that the runtime won't allow this to happen.)</p> <p><strong>Edit:</strong> So I've decided to go with an Interlocked CompareExchange method inspired by <a href="http://www.bluebytesoftware.com/blog/2007/11/17/ImmutableTypesCanCopyTheWorldSafely.aspx" rel="noreferrer">this article by Joe Duffy</a>.</p> <p>Basically:</p> <pre><code>private ReadOnlyCollection&lt;SomeImmutableType&gt; m_PropName = null; public ReadOnlyCollection&lt;SomeImmutableType&gt; PropName { get { if(null == m_PropName) { ReadOnlyCollection&lt;SomeImmutableType&gt; temp = /* do lazy init */; System.Threading.Interlocked(ref m_PropName, temp, null); } return m_PropName; } } </code></pre> <p>This is supposed to ensure that all threads that call this method on this object instance will get a reference to the same object, so the == operator will work. It is possible to have wasted work, which is fine - it just makes this an optimistic algorithm.</p> <p>As noted in some comments below, this depends on the .NET 2.0 memory model to work. Otherwise, m_PropName should be declared volatile.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload