ThreadLocal.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / clr / src / BCL / System / Threading / ThreadLocal.cs / 1305376 / ThreadLocal.cs

                            #pragma warning disable 0420 
// ==++==
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 
// 
// ThreadLocal.cs
// 
// [....]
//
// A class that provides a simple, lightweight implementation of thread-local lazy-initialization, where a value is initialized once per accessing
// thread; this provides an alternative to using a ThreadStatic static variable and having 
// to check the variable prior to every access to see if it's been initialized.
// 
// 
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 

using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions; 
using System.Diagnostics;
using System.Runtime.Serialization; 
using System.Collections.Concurrent; 
using System.Diagnostics.Contracts;
namespace System.Threading 
{


    ///  
    /// A seprate non generic class that contains a global counter for fast path instances for all Ts that has been created, and adds an upper limit for all instances
    /// that uses the fast path, if this limit has been reached, all new instances will use the slow path 
    ///  
    internal static class ThreadLocalGlobalCounter
    { 
        internal static volatile int s_fastPathCount; // the current fast path instances count
        internal static int MAXIMUM_GLOBAL_COUNT = ThreadLocal.MAXIMUM_TYPES_LENGTH * 4; // the maximum number og instances that should use the fast path

    } 

    ///  
    /// Provides thread-local storage of data. 
    /// 
    /// Specifies the type of data stored per-thread. 
    /// 
    /// 
    /// With the exception of , all public and protected members of
    ///  are thread-safe and may be used 
    /// concurrently from multiple threads.
    ///  
    ///  
    [DebuggerTypeProxy(typeof(SystemThreading_ThreadLocalDebugView<>))]
    [DebuggerDisplay("IsValueCreated={IsValueCreated}, Value={ValueForDebugDisplay}")] 
    [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
    public class ThreadLocal : IDisposable
    {
 
        /*
          * The normal path to create a ThreadLocal object is to create ThreadLocalStorage slots but unfortunately this is very slow 
          * comparing to ThreadStatic types. 
          * The workaround to avoid this is to use generic types that has a ThreadStatic fields, so for every generic type we will get a fresh
          * ThreadStatic object, and there is an index for each ThreadLocal instance that maps to the generic types used. 
          * We are using here 16 dummy types that are used as a generic parameter for the Type that has the ThreadStatic field, this type has 3
          * generic types, so the maximum ThreadLocal of a certain type that can be created together using this technique is 16^3 which is very large, and this can be
          * expanded in the future by increasing the generic parameter to 4 if we are seeing customer demands.
          * If we have used all combinations, we go to the slow path by creating ThreadLocalStorage objects. 
          * The ThreadLocal class has a finalizer to return the instance index back to the pool, so the new instance first checks the pool if it has unused indices or not, if so
          * it gets an index otherwise it will acquire a new index by incrementing a static global counter. 
          * 
          */
 
        #region Static fields
        // Don't open this region
        #region Dummy Types
        class C0 { } 
        class C1 { }
        class C2 { } 
        class C3 { } 
        class C4 { }
        class C5 { } 
        class C6 { }
        class C7 { }
        class C8 { }
        class C9 { } 
        class C10 { }
        class C11 { } 
        class C12 { } 
        class C13 { }
        class C14 { } 
        class C15 { }


        private static Type[] s_dummyTypes = {  typeof(C0), typeof(C1), typeof(C2), typeof(C3), typeof(C4), typeof(C5), typeof(C6), typeof(C7), 
                                                typeof(C8), typeof(C9), typeof(C10), typeof(C11), typeof(C12), typeof(C13), typeof(C14), typeof(C15)
                                             }; 
 
        #endregion
 
        // a global static counter that gives a unique index for each instance of type T
        private static int s_currentTypeId = -1;

        // The indices pool 
        private static ConcurrentStack s_availableIndices = new ConcurrentStack();
 
 
        // The number of generic parameter to the type
        private static int TYPE_DIMENSIONS = typeof(GenericHolder<,,>).GetGenericArguments().Length; 

        // Maximum types combinations
        internal static int MAXIMUM_TYPES_LENGTH = (int)Math.Pow(s_dummyTypes.Length, TYPE_DIMENSIONS - 1);
 
        #endregion
 
        // The holder base class the holds the actual value, this can be either" 
        // - GenericHolder class if it is using the fast path (generic combinations)
        // - TLSHolder class if it using the slow path 
        // - Null if the object has been disposed
        private HolderBase m_holder;

        // a delegate that returns the created value, if null the created value will be default(T) 
        private Func m_valueFactory;
 
        // The current instace index for type T, this could be any number between 0 and MAXIMUM_TYPES_LENGTH -1 if it is using the fast path, 
        // or -1 if it is using the slow path
        private int m_currentInstanceIndex; 

        /// 
        /// Initializes the  instance.
        ///  
        [System.Security.SecuritySafeCritical]
        public ThreadLocal() 
        { 
            // Find a combination index if available, and set the m_currentInstanceIndex to that index
            if (FindNextTypeIndex()) 
            {
                // If there is an index available, use the fast path and get the genertic parameter types
                Type[] genericTypes = GetTypesFromIndex();
                PermissionSet permission = new PermissionSet(PermissionState.Unrestricted); 
                permission.Assert();
                try 
                { 
                    m_holder = (HolderBase)Activator.CreateInstance(typeof(GenericHolder<,,>).MakeGenericType(genericTypes));
                } 
                finally
                {
                    PermissionSet.RevertAssert();
                } 
            }
            else 
            { 
                // all indices are being used, go with the slow path
                m_holder = new TLSHolder(); 
            }

        }
 
        /// 
        /// Initializes the  instance with the 
        /// specified  function. 
        /// 
        ///  
        /// The  invoked to produce a lazily-initialized value when
        /// an attempt is made to retrieve  without it having been previously initialized.
        /// 
        ///  
        ///  is a null reference (Nothing in Visual Basic).
        ///  
        public ThreadLocal(Func valueFactory) 
            : this()
        { 
            if (valueFactory == null)
                throw new ArgumentNullException("valueFactory");

            m_valueFactory = valueFactory; 
        }
 
        ///  
        /// Releases the resources used by this  instance.
        ///  
        ~ThreadLocal()
        {
            // finalizer to return the type combination index to the pool
            Dispose(false); 
        }
 
        #region IDisposable Members 

        ///  
        /// Releases the resources used by this  instance.
        /// 
        /// 
        /// Unlike most of the members of , this method is not thread-safe. 
        /// 
        public void Dispose() 
        { 
            Dispose(true);
            GC.SuppressFinalize(this); 
        }

        /// 
        /// Releases the resources used by this  instance. 
        /// 
        ///  
        /// A Boolean value that indicates whether this method is being called due to a call to . 
        /// 
        ///  
        /// Unlike most of the members of , this method is not thread-safe.
        /// 
        protected virtual void Dispose(bool disposing)
        { 
            int index = this.m_currentInstanceIndex;
 
            // if the current instance was using the fast path, we should return its combinations type index to the pool to allow reusing it later 
            if (index > -1 && Interlocked.CompareExchange(ref m_currentInstanceIndex, -1, index) == index) // reset the index to -1 to avoid multiple dispose call
            { 
                s_availableIndices.Push(index);
            }
            m_holder = null;
        } 

        #endregion 
 

        ///  
        /// Tries to get a unique index for the current instance of type T, it first tries to get it from the pool if it is not empty, otherwise it
        /// increments the global counter if it is still below the maximum, otherwise it fails and returns -1
        /// 
        /// True if there is an index available, false otherwise 
        private bool FindNextTypeIndex()
        { 
 
            int index = -1;
            // Look at the pool first 
            if (s_availableIndices.TryPop(out index))
            {
                Contract.Assert(index >= 0 && index < MAXIMUM_TYPES_LENGTH);
                m_currentInstanceIndex = index; 
                return true;
            } 
 
            // check if we reached the maximum allowed instaces for the fast path for type T
            // and checkif we reached the global maximum for all Ts 
            if (s_currentTypeId < MAXIMUM_TYPES_LENGTH - 1
                && ThreadLocalGlobalCounter.s_fastPathCount < ThreadLocalGlobalCounter.MAXIMUM_GLOBAL_COUNT
                && Interlocked.Increment(ref ThreadLocalGlobalCounter.s_fastPathCount) <= ThreadLocalGlobalCounter.MAXIMUM_GLOBAL_COUNT)
            { 
                // There is no indices in the pool, check if we have more indices available
                index = Interlocked.Increment(ref s_currentTypeId); 
                if (index < MAXIMUM_TYPES_LENGTH) 
                {
                    m_currentInstanceIndex = index; 
                    return true;
                }
            }
            // no indices available, set the m_currentInstanceIndex to -1 
            m_currentInstanceIndex = -1;
            return false; 
 
        }
 
        /// 
        /// Gets an array of types that will be used as generic parameters for the GenericHolder class
        /// 
        /// The types array 
        private Type[] GetTypesFromIndex()
        { 
            // The array length is equal to the dimensions 
            Type[] types = new Type[TYPE_DIMENSIONS];
            types[0] = typeof(T); // the first one for the Type T 

            // This calculates the dimension indices based on the m_currentInstanceIndex, it is like converting from decimal number formats to base N format
            // where N is the s_dummyTypes.Length, and each ith digit in this format represents an index in the ith dimension
            // ex: if we are using 4 dimensions, we we want to convert the index from decimal to the base 16 , so the index 255 will be 0 0 15 15 
            int index = m_currentInstanceIndex;
            for (int i = 1; i < TYPE_DIMENSIONS; i++) 
            { 
                types[i] = s_dummyTypes[index % s_dummyTypes.Length];
                index /= s_dummyTypes.Length; 
            }

            return types;
        } 

        /// Creates and returns a string representation of this instance for the current thread. 
        /// The result of calling  on the . 
        /// 
        /// The  for the current thread is a null reference (Nothing in Visual Basic). 
        /// 
        /// 
        /// The initialization function referenced  in an improper manner.
        ///  
        /// 
        /// The  instance has been disposed. 
        ///  
        /// 
        /// Calling this method forces initialization for the current thread, as is the 
        /// case with accessing  directly.
        /// 
        public override string ToString()
        { 
            return Value.ToString();
        } 
 
        /// 
        /// Gets or sets the value of this instance for the current thread. 
        /// 
        /// 
        /// The initialization function referenced  in an improper manner.
        ///  
        /// 
        /// The  instance has been disposed. 
        ///  
        /// 
        /// If this instance was not previously initialized for the current thread, 
        /// accessing  will attempt to initialize it. If an initialization function was
        /// supplied during the construction, that initialization will happen by invoking the function
        /// to retrieve the initial value for .  Otherwise, the default value of
        ///  will be used. 
        /// 
        [DebuggerBrowsable(DebuggerBrowsableState.Never)] 
        public T Value 
        {
            get 
            {
                // Throw if disposed
                if (m_holder == null)
                    throw new ObjectDisposedException(Environment.GetResourceString("ThreadLocal_Disposed")); 

                Boxed boxed = m_holder.Boxed; 
                if (boxed == null || boxed.m_ownerHolder != m_holder) 
                {
                    // We call NOCTD to abort attempts by the debugger to evaluate this property (eg on mouseover) 
                    //   (the debugger proxy is the correct way to look at state/value of this object)
#if !PFX_LEGACY_3_5
                    Debugger.NotifyOfCrossThreadDependency();
#endif 
                    boxed = CreateValue();
                } 
                return boxed.Value; 
            }
            set 
            {
                // Throw if disposed
                if (m_holder == null)
                    throw new ObjectDisposedException(Environment.GetResourceString("ThreadLocal_Disposed")); 

                Boxed boxed = m_holder.Boxed; 
                if (boxed != null && boxed.m_ownerHolder == m_holder) 
                    boxed.Value = value;
                else 
                    m_holder.Boxed = new Boxed { Value = value, m_ownerHolder = m_holder };
            }
        }
 
        /// 
        /// Private helper function to lazily create the value using the calueSelector if specified in the constructor or the default parameterless constructor 
        ///  
        /// Returns the boxed object
        private Boxed CreateValue() 
        {
            Boxed boxed = new Boxed();
            boxed.m_ownerHolder = m_holder;
            boxed.Value = m_valueFactory == null ? default(T) : m_valueFactory(); 
            if (m_holder.Boxed != null && m_holder.Boxed.m_ownerHolder == m_holder)
                throw new InvalidOperationException(Environment.GetResourceString("ThreadLocal_Value_RecursiveCallsToValue")); 
 
            m_holder.Boxed = boxed;
 
            return boxed;
        }

        ///  
        /// Gets whether  is initialized on the current thread.
        ///  
        ///  
        /// The  instance has been disposed.
        ///  
        public bool IsValueCreated
        {
            get
            { 
                // Throw if disposed
                if (m_holder == null) 
                    throw new ObjectDisposedException(Environment.GetResourceString("ThreadLocal_Disposed")); 

                Boxed boxed = m_holder.Boxed; 
                return (boxed != null && boxed.m_ownerHolder == m_holder);
            }
        }
 

        /// Gets the value of the ThreadLocal<T> for debugging display purposes. It takes care of getting 
        /// the value for the current thread in the ThreadLocal mode. 
        internal T ValueForDebugDisplay
        { 
            get
            {
                if (m_holder == null || m_holder.Boxed == null || m_holder.Boxed.m_ownerHolder != m_holder) // if disposed or value not initialized yet returns default(T)
                    return default(T); 
                return m_holder.Boxed.Value;
            } 
        } 

        ///  
        /// The base abstract class for the holder
        /// 
        abstract class HolderBase
        { 
            internal abstract Boxed Boxed { get; set; }
        } 
 

        ///  
        /// The TLS holder representation
        /// 
        sealed class TLSHolder : HolderBase
        { 

            private LocalDataStoreSlot m_slot = Thread.AllocateDataSlot(); 
 
            internal override Boxed Boxed
            { 
                get { return (Boxed)Thread.GetData(m_slot); }
                set { Thread.SetData(m_slot, value); }
            }
        } 

        ///  
        /// The generic holder representation 
        /// 
        /// Dummy param 
        /// Dummy param
        /// Dummy param
        sealed class GenericHolder : HolderBase
        { 
            [ThreadStatic]
            private static Boxed s_value; 
 
            internal override Boxed Boxed
            { 
                get { return s_value; }
                set { s_value = value; }
            }
        } 

        ///  
        /// wrapper to the actual value 
        /// 
        class Boxed 
        {
            internal T Value;

            // reference back to the holder as an identifier to the current ThreadLocal instace, to avoid the case where a thread create a ThreadLocal object dispose it 
            // then create a nother object of the same type, the new object will point to the old object value but by setting the holder we check if the boxed holder matched the current
            // instance holder or not 
            internal HolderBase m_ownerHolder; 
        }
 

    }

    /// A debugger view of the ThreadLocal<T> to surface additional debugging properties and 
    /// to ensure that the ThreadLocal<T> does not become initialized if it was not already.
    internal sealed class SystemThreading_ThreadLocalDebugView 
    { 
        //The ThreadLocal object being viewed.
        private readonly ThreadLocal m_tlocal; 

        /// Constructs a new debugger view object for the provided ThreadLocal object.
        /// A ThreadLocal object to browse in the debugger.
        public SystemThreading_ThreadLocalDebugView(ThreadLocal tlocal) 
        {
            m_tlocal = tlocal; 
        } 

        /// Returns whether the ThreadLocal object is initialized or not. 
        public bool IsValueCreated
        {
            get { return m_tlocal.IsValueCreated; }
        } 

        /// Returns the value of the ThreadLocal object. 
        public T Value 
        {
            get 
            {
                return m_tlocal.ValueForDebugDisplay;
            }
        } 

 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK