Example #1
0
        /// <summary>
        /// local helper method to initialize the value
        /// </summary>
        /// <returns>The inititialized T value</returns>
        private T LazyInitValue()
        {
            Boxed boxed = null;
            LazyThreadSafetyMode mode = Mode;

            if (mode == LazyThreadSafetyMode.None)
            {
                boxed   = CreateValue();
                m_boxed = boxed;
            }
            else if (mode == LazyThreadSafetyMode.PublicationOnly)
            {
                boxed = CreateValue();
                if (boxed == null ||
                    Interlocked.CompareExchange(ref m_boxed, boxed, null) != null)
                {
                    // If CreateValue returns null, it means another thread successfully invoked the value factory
                    // and stored the result, so we should just take what was stored.  If CreateValue returns non-null
                    // but we lose the ---- to store the single value, again we should just take what was stored.
                    boxed = (Boxed)m_boxed;
                }
                else
                {
                    // We successfully created and stored the value.  At this point, the value factory delegate is
                    // no longer needed, and we don't want to hold onto its resources.
                    m_valueFactory = ALREADY_INVOKED_SENTINEL;
                }
            }
            else
            {
                object threadSafeObj = Volatile.Read(ref m_threadSafeObj);
                try
                {
                    if (threadSafeObj != (object)ALREADY_INVOKED_SENTINEL)
                    {
                        Monitor.Enter(threadSafeObj);
                    }
                    else
                    {
                        Guard.Assert(m_boxed != null, new ArgumentException());
                    }

                    if (m_boxed == null)
                    {
                        boxed   = CreateValue();
                        m_boxed = boxed;
                        Volatile.Write(ref m_threadSafeObj, ALREADY_INVOKED_SENTINEL);
                    }
                    else // got the lock but the value is not null anymore, check if it is created by another thread or faulted and throw if so
                    {
                        Guard.Assert(boxed != null, new ArgumentException());
                    }
                }
                finally
                {
                    Monitor.Exit(threadSafeObj);
                }
            }
            Guard.Assert(boxed != null, new ArgumentException());
            return(boxed.m_value);
        }