Exemple #1
0
        /// <summary>
        /// Resizes a table to a certain length (or larger).
        /// </summary>
        private void GrowTable(ref LinkedSlotVolatile[] table, int minLength)
        {
            Contract.Assert(table.Length < minLength);

            // Determine the size of the new table and allocate it.
            int newLen = GetNewTableSize(minLength);

            LinkedSlotVolatile[] newTable = new LinkedSlotVolatile[newLen];

            //
            // The lock is necessary to avoid a race with ThreadLocal.Dispose. GrowTable has to point all
            // LinkedSlot instances referenced in the old table to reference the new table. Without locking,
            // Dispose could use a stale SlotArray reference and clear out a slot in the old array only, while
            // the value continues to be referenced from the new (larger) array.
            //
            lock (s_idManager)
            {
                for (int i = 0; i < table.Length; i++)
                {
                    LinkedSlot linkedSlot = table[i].Value;
                    if (linkedSlot != null && linkedSlot.SlotArray != null)
                    {
                        linkedSlot.SlotArray = newTable;
                        newTable[i]          = table[i];
                    }
                }
            }

            table = newTable;
        }
Exemple #2
0
        public override void OnSubInspectorGUI()
        {
            LinkedSlot s = target as LinkedSlot;

            s.SourceSlot = EditorGUILayout.ObjectField("Source Slot", s.SourceSlot, typeof(PGISlot), true) as PGISlot;
            SlotInspector();
        }
Exemple #3
0
        /// <summary>
        /// Creates a LinkedSlot and inserts it into the linked list for this ThreadLocal instance.
        /// </summary>
        private void CreateLinkedSlot(LinkedSlotVolatile[] slotArray, int id, T value)
        {
            // Create a LinkedSlot
            var linkedSlot = new LinkedSlot(slotArray);

            // Insert the LinkedSlot into the linked list maintained by this ThreadLocal<> instance and into the slot array
            lock (s_idManager)
            {
                // Check that the instance has not been disposed. It is important to check this under a lock, since
                // Dispose also executes under a lock.
                if (!_initialized)
                {
                    throw new ObjectDisposedException(SR.ThreadLocal_Disposed);
                }

                LinkedSlot firstRealNode = _linkedSlot._next;

                // Insert linkedSlot between nodes m_linkedSlot and firstRealNode.
                // (_linkedSlot is the dummy head node that should always be in the front.)
                linkedSlot._next     = firstRealNode;
                linkedSlot._previous = _linkedSlot;
                linkedSlot._value    = value;

                if (firstRealNode != null)
                {
                    firstRealNode._previous = linkedSlot;
                }
                _linkedSlot._next = linkedSlot;

                // Assigning the slot under a lock prevents a race condition with Dispose (dispose also acquires the lock).
                // Otherwise, it would be possible that the ThreadLocal instance is disposed, another one gets created
                // with the same ID, and the write would go to the wrong instance.
                slotArray[id].Value = linkedSlot;
            }
        }
Exemple #4
0
        private void SetValueSlow(T value, LinkedSlotVolatile[] slotArray)
        {
            int id = ~m_idComplement;

            // If the object has been disposed, id will be -1.
            if (id < 0)
            {
                throw new ObjectDisposedException(Environment.GetResourceString("ThreadLocal_Disposed"));
            }

            // If a slot array has not been created on this thread yet, create it.
            if (slotArray == null)
            {
                slotArray             = new LinkedSlotVolatile[GetNewTableSize(id + 1)];
                ts_finalizationHelper = new FinalizationHelper(slotArray, m_trackAllValues);
                ts_slotArray          = slotArray;
            }

            // If the slot array is not big enough to hold this ID, increase the table size.
            if (id >= slotArray.Length)
            {
                GrowTable(ref slotArray, id + 1);
                ts_finalizationHelper.SlotArray = slotArray;
                ts_slotArray = slotArray;
            }

            // If we are using the slot in this table for the first time, create a new LinkedSlot and add it into
            // the linked list for this ThreadLocal instance.
            if (slotArray[id].Value == null)
            {
                CreateLinkedSlot(slotArray, id, value);
            }
            else
            {
                // Volatile read of the LinkedSlotVolatile.Value property ensures that the m_initialized read
                // that follows will not be reordered before the read of slotArray[id].
                LinkedSlot slot = slotArray[id].Value;

                // It is important to verify that the ThreadLocal instance has not been disposed. The check must come
                // after capturing slotArray[id], but before assigning the value into the slot. This ensures that
                // if this ThreadLocal instance was disposed on another thread and another ThreadLocal instance was
                // created, we definitely won't assign the value into the wrong instance.

                if (!m_initialized)
                {
                    throw new ObjectDisposedException(Environment.GetResourceString("ThreadLocal_Disposed"));
                }

                slot.Value = value;
            }
        }
Exemple #5
0
        /// <summary>Gets all of the threads' values in a list.</summary>
        private List <T> GetValuesAsList()
        {
            List <T> valueList = new List <T>();
            int      id        = ~m_idComplement;

            if (id == -1)
            {
                return(null);
            }

            // Walk over the linked list of slots and gather the values associated with this ThreadLocal instance.
            for (LinkedSlot linkedSlot = m_linkedSlot.Next; linkedSlot != null; linkedSlot = linkedSlot.Next)
            {
                // We can safely read linkedSlot.Value. Even if this ThreadLocal has been disposed in the meantime, the LinkedSlot
                // objects will never be assigned to another ThreadLocal instance.
                valueList.Add(linkedSlot.Value);
            }

            return(valueList);
        }
Exemple #6
0
        /// <summary>
        /// Releases the resources used by this <see cref="T:System.Threading.ThreadLocal{T}" /> instance.
        /// </summary>
        /// <param name="disposing">
        /// A Boolean value that indicates whether this method is being called due to a call to <see cref="Dispose()"/>.
        /// </param>
        /// <remarks>
        /// Unlike most of the members of <see cref="T:System.Threading.ThreadLocal{T}"/>, this method is not thread-safe.
        /// </remarks>
        protected virtual void Dispose(bool disposing)
        {
            int id;

            lock (s_idManager)
            {
                id             = ~m_idComplement;
                m_idComplement = 0;

                if (id < 0 || !m_initialized)
                {
                    Contract.Assert(id >= 0 || !m_initialized, "expected id >= 0 if initialized");

                    // Handle double Dispose calls or disposal of an instance whose constructor threw an exception.
                    return;
                }
                m_initialized = false;

                for (LinkedSlot linkedSlot = m_linkedSlot.Next; linkedSlot != null; linkedSlot = linkedSlot.Next)
                {
                    LinkedSlotVolatile[] slotArray = linkedSlot.SlotArray;

                    if (slotArray == null)
                    {
                        // The thread that owns this slotArray has already finished.
                        continue;
                    }

                    // Remove the reference from the LinkedSlot to the slot table.
                    linkedSlot.SlotArray = null;

                    // And clear the references from the slot table to the linked slot and the value so that
                    // both can get garbage collected.
                    slotArray[id].Value.Value = default(T);
                    slotArray[id].Value       = null;
                }
            }
            m_linkedSlot = null;
            s_idManager.ReturnId(id);
        }