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 another thread set the value 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);
                bool   lockTaken     = false;
                try
                {
                    if (threadSafeObj != (object)ALREADY_INVOKED_SENTINEL)
                    {
                        Monitor.Enter(threadSafeObj, ref lockTaken);
                    }
                    else
                    {
                        Contract.Assert(m_boxed != null);
                    }

                    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
                    {
                        boxed = m_boxed as Boxed;
                        if (boxed == null) // it is not Boxed, so it is a LazyInternalExceptionHolder
                        {
                            LazyInternalExceptionHolder exHolder = m_boxed as LazyInternalExceptionHolder;
                            Contract.Assert(exHolder != null);
                            exHolder.m_edi.Throw();
                        }
                    }
                }
                finally
                {
                    if (lockTaken)
                    {
                        Monitor.Exit(threadSafeObj);
                    }
                }
            }
            Contract.Assert(boxed != null);
            return(boxed.m_value);
        }
Example #2
0
        /// <summary>
        /// Allocates a generic fragment with a specified length.
        /// </summary>
        /// <param name="size">The number of bytes to allocate.</param>
        /// <param name="tries">
        /// The number of fails before switching to another lane.
        /// If 0 the HighwaySettings.LaneAllocTries value is used.
        /// </param>
        /// <param name="awaitMS">The awaitMS for each try</param>
        /// <returns>A new fragment.</returns>
        /// <exception cref="System.ArgumentOutOfRangeException">
        /// If size is negative or greater than HighwaySettings.MAX_LANE_CAPACITY.
        /// </exception>
        /// <exception cref="System.MemoryLaneException">
        /// Code.NotInitialized: when the lanes are not initialized.
        /// Code.NewLaneAllocFail: after an unsuccessful attempt to allocate a fragment in a dedicated new lane.
        /// One should never see this one!
        /// </exception>
        /// <exception cref="ObjectDisposedException">If the MemoryCarriage is disposed.</exception>
        public F Alloc(int size, int tries = 0, int awaitMS = 5)
        {
            if (isDisposed)
            {
                throw new ObjectDisposedException("MemoryCarriage");
            }
            if (Lanes == null || Lanes.AllocatedSlots == 0)
            {
                throw new MemoryLaneException(MemoryLaneException.Code.NotInitialized);
            }
            if (size < 0 || size > HighwaySettings.MAX_LANE_CAPACITY)
            {
                throw new ArgumentOutOfRangeException("size");
            }
            if (tries == 0)
            {
                tries = settings.LaneAllocTries;
            }

            F   frag       = null;
            var lanesCount = Lanes.ItemsCount;

            // Start from the oldest lane and cycle all lanes a few times before making a new lane
            for (var laps = 0; laps < settings.LapsBeforeNewLane; laps++)
            {
                for (var i = 0; i < lanesCount; i++)
                {
                    var lane = Lanes[i];

                    if (lane != null && !lane.IsClosed && !lane.IsDisposed)
                    {
                        frag = createFragment(lane, size, tries, awaitMS);

                        if (frag != null)
                        {
                            Volatile.Write(ref lastAllocTickAnyLane, DateTime.Now.Ticks);
                            return(frag);
                        }
                    }
                }
            }

            // limits the concurrent lane allocations
            if (noluckGate.Wait(settings.NewLaneAllocationTimeoutMS))
            {
                // Try again, there is at least one new lane
                if (lanesCount < Lanes.ItemsCount)
                {
                    noluckGate.Release();
                    return(Alloc(size, tries, awaitMS));
                }
                else
                {
                    try
                    {
                        // [i] No luck, create a new lane and do not publish it before getting a fragment

                        var ccMakers     = settings.ConcurrentNewLaneAllocations - noluckGate.CurrentCount;
                        var nextCapacity = settings.NextCapacity(Lanes.AppendIndex + ccMakers);
                        var cap          = size > nextCapacity ? size : nextCapacity;
                        var ml           = allocLane(cap, true);

                        // Could be null if the MaxLanesCount or MaxBytesCount exceptions are ignored.
                        // The consumer can infer that by checking if the fragment is null.
                        if (ml != null)
                        {
                            frag = createFragment(ml, size, tries, awaitMS);

                            if (frag == null)
                            {
                                throw new MemoryLaneException(
                                          MemoryLaneException.Code.NewLaneAllocFail,
                                          string.Format("Failed to allocate {0} bytes on a dedicated lane.", size));
                            }

                            Lanes.Append(ml);
                            Volatile.Write(ref lastAllocTickAnyLane, DateTime.Now.Ticks);
                        }
                    }
                    finally { noluckGate.Release(); }
                }
            }

            return(frag);
        }