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
        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;
            }
        }