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. ////// [DebuggerTypeProxy(typeof(SystemThreading_ThreadLocalDebugView<>))] [DebuggerDisplay("IsValueCreated={IsValueCreated}, Value={ValueForDebugDisplay}")] [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)] public class ThreadLocal/// With the exception of ///, all public and protected members of /// are thread-safe and may be used /// concurrently from multiple threads. /// : 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 [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(); } } ///instance. /// /// Initializes the /// /// Theinstance with the /// specified function. /// invoked to produce a lazily-initialized value when /// an attempt is made to retrieve without it having been previously initialized. /// /// /// public ThreadLocal(Funcis a null reference (Nothing in Visual Basic). /// valueFactory) : this() { if (valueFactory == null) throw new ArgumentNullException("valueFactory"); m_valueFactory = valueFactory; } /// /// Releases the resources used by this ~ThreadLocal() { // finalizer to return the type combination index to the pool Dispose(false); } #region IDisposable Members ///instance. /// /// Releases the resources used by this ///instance. /// /// Unlike most of the members of public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } ///, this method is not thread-safe. /// /// Releases the resources used by this /// /// A Boolean value that indicates whether this method is being called due to a call toinstance. /// . /// /// /// Unlike most of the members of 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 ///, this method is not thread-safe. /// /// 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 public override string ToString() { return Value.ToString(); } ///directly. /// /// 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 [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 }; } } ///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. /// /// 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 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); } } ///instance has been disposed. /// 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(ThreadLocaltlocal) { 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
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ExeConfigurationFileMap.cs
- SqlNodeAnnotation.cs
- InvalidateEvent.cs
- CookielessHelper.cs
- TemplateControl.cs
- TypeTypeConverter.cs
- TrackingProfileSerializer.cs
- ByteStreamMessageEncoderFactory.cs
- PrintingPermissionAttribute.cs
- hresults.cs
- CallbackDebugElement.cs
- XmlSchemaImporter.cs
- DiagnosticsConfiguration.cs
- AsynchronousChannelMergeEnumerator.cs
- UrlPropertyAttribute.cs
- ConnectionManager.cs
- PlainXmlDeserializer.cs
- QuotedPairReader.cs
- SinglePageViewer.cs
- BuildProviderAppliesToAttribute.cs
- messageonlyhwndwrapper.cs
- ClientScriptManagerWrapper.cs
- StatusBarPanel.cs
- WindowInteropHelper.cs
- BitmapEffect.cs
- GuidelineSet.cs
- odbcmetadatacollectionnames.cs
- _HelperAsyncResults.cs
- AlternateViewCollection.cs
- JavaScriptString.cs
- XmlSchemaAll.cs
- Converter.cs
- SudsParser.cs
- DefaultTextStore.cs
- FloaterBaseParaClient.cs
- smtppermission.cs
- TimeSpanMinutesConverter.cs
- RuntimeWrappedException.cs
- SiteMap.cs
- PixelShader.cs
- DbConnectionOptions.cs
- Canvas.cs
- PrimitiveList.cs
- FloaterParagraph.cs
- SessionStateSection.cs
- SafeArrayTypeMismatchException.cs
- CodeGen.cs
- HashHelper.cs
- MouseDevice.cs
- ToolboxCategory.cs
- ConstructorExpr.cs
- ConnectionStringsSection.cs
- WindowsScrollBar.cs
- RepeatBehavior.cs
- Vector3D.cs
- RangeValuePatternIdentifiers.cs
- GridViewCancelEditEventArgs.cs
- DesignerSerializerAttribute.cs
- SqlCommand.cs
- BidOverLoads.cs
- StringArrayConverter.cs
- EventToken.cs
- TabOrder.cs
- XmlIlTypeHelper.cs
- DataGridViewCellErrorTextNeededEventArgs.cs
- SchemaTypeEmitter.cs
- ConnectionManagementElementCollection.cs
- InvalidOperationException.cs
- DesignerActionMethodItem.cs
- LocalizationComments.cs
- InputScope.cs
- DesignerOptionService.cs
- _Rfc2616CacheValidators.cs
- PeerResolverBindingElement.cs
- DesignTimeHTMLTextWriter.cs
- ActionNotSupportedException.cs
- ActivityIdHeader.cs
- PropertyChangingEventArgs.cs
- CalloutQueueItem.cs
- XamlHostingSection.cs
- AlphabeticalEnumConverter.cs
- ContentPlaceHolder.cs
- Interlocked.cs
- CharEnumerator.cs
- PriorityBindingExpression.cs
- DesignerActionPanel.cs
- BufferedGraphicsManager.cs
- WrappedIUnknown.cs
- AutomationEventArgs.cs
- ClosableStream.cs
- Part.cs
- PathGeometry.cs
- XmlSerializerNamespaces.cs
- HMAC.cs
- ContractUtils.cs
- BamlLocalizerErrorNotifyEventArgs.cs
- VarRefManager.cs
- PeerNameRecordCollection.cs
- Quaternion.cs
- ConfigXmlText.cs