Code:
/ 4.0 / 4.0 / 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.
#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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- HelpInfo.cs
- XsltException.cs
- IncrementalCompileAnalyzer.cs
- WarningException.cs
- RequiredFieldValidator.cs
- EntityKey.cs
- RightsManagementEncryptionTransform.cs
- TypeUtil.cs
- XmlSchemaObjectTable.cs
- HtmlInputText.cs
- Aes.cs
- Assembly.cs
- IItemProperties.cs
- Membership.cs
- documentsequencetextpointer.cs
- PackageDigitalSignature.cs
- ImageFormatConverter.cs
- CommentEmitter.cs
- ListBoxAutomationPeer.cs
- VSWCFServiceContractGenerator.cs
- StaticSiteMapProvider.cs
- MatrixStack.cs
- PrimitiveXmlSerializers.cs
- DisplayInformation.cs
- CustomAttributeFormatException.cs
- WindowsEditBoxRange.cs
- SqlAliasesReferenced.cs
- DataBinder.cs
- SessionStateUtil.cs
- OleDbReferenceCollection.cs
- ScriptControl.cs
- ExtensionElementCollection.cs
- SmiTypedGetterSetter.cs
- SchemaHelper.cs
- RelatedCurrencyManager.cs
- SamlEvidence.cs
- ExpressionWriter.cs
- RuntimeConfigLKG.cs
- ThrowHelper.cs
- ExpressionConverter.cs
- ControlAdapter.cs
- SystemPens.cs
- SplitterCancelEvent.cs
- ZipIOLocalFileBlock.cs
- CodeAccessPermission.cs
- FunctionImportMapping.ReturnTypeRenameMapping.cs
- Zone.cs
- FormatterServices.cs
- SqlMultiplexer.cs
- AsyncStreamReader.cs
- DoubleStorage.cs
- ComplexTypeEmitter.cs
- ValueTypeFixupInfo.cs
- LinkConverter.cs
- WindowsNonControl.cs
- SmiMetaDataProperty.cs
- Converter.cs
- WebPartDisplayModeCancelEventArgs.cs
- SchemaDeclBase.cs
- Point.cs
- PointLightBase.cs
- ScopedMessagePartSpecification.cs
- Rules.cs
- DataBindingHandlerAttribute.cs
- EventMetadata.cs
- KnownTypeAttribute.cs
- BinarySerializer.cs
- SmtpSpecifiedPickupDirectoryElement.cs
- ResourceCategoryAttribute.cs
- LinkButton.cs
- CompositeFontInfo.cs
- TagPrefixInfo.cs
- MailAddressCollection.cs
- shaperfactoryquerycacheentry.cs
- RouteValueDictionary.cs
- CategoryValueConverter.cs
- precedingquery.cs
- InvokeHandlers.cs
- AutomationEvent.cs
- RenamedEventArgs.cs
- DefaultMergeHelper.cs
- RecognizerStateChangedEventArgs.cs
- ParameterElementCollection.cs
- RSAPKCS1KeyExchangeDeformatter.cs
- RegexWorker.cs
- CodePrimitiveExpression.cs
- ConstantCheck.cs
- Predicate.cs
- FixedPageProcessor.cs
- OdbcConnection.cs
- Certificate.cs
- MatrixIndependentAnimationStorage.cs
- RegexNode.cs
- ViewCellSlot.cs
- KeyMatchBuilder.cs
- AuthenticatedStream.cs
- PageContent.cs
- HttpConfigurationSystem.cs
- LambdaCompiler.Address.cs
- SplashScreen.cs