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
- Compiler.cs
- RegionIterator.cs
- TranslateTransform3D.cs
- FileDialog.cs
- AudioBase.cs
- SerializationSectionGroup.cs
- CodeTypeDelegate.cs
- BufferAllocator.cs
- StorageBasedPackageProperties.cs
- FilterException.cs
- RadioButtonPopupAdapter.cs
- TextBoxView.cs
- InfoCardRSAOAEPKeyExchangeFormatter.cs
- TabRenderer.cs
- InvalidDataException.cs
- MetadataItemEmitter.cs
- SqlDataSource.cs
- objectresult_tresulttype.cs
- EdgeProfileValidation.cs
- SafeSecurityHandles.cs
- PointCollectionValueSerializer.cs
- SessionStateItemCollection.cs
- DecoderBestFitFallback.cs
- AssemblyBuilder.cs
- URLEditor.cs
- ServerIdentity.cs
- ToolStripItemCollection.cs
- KeyMatchBuilder.cs
- ColorKeyFrameCollection.cs
- TraceLevelHelper.cs
- DataBindingHandlerAttribute.cs
- DLinqTableProvider.cs
- Int32RectConverter.cs
- XmlTextReader.cs
- XmlSchemaAppInfo.cs
- DetailsViewUpdateEventArgs.cs
- ListViewUpdatedEventArgs.cs
- XmlObjectSerializerWriteContextComplexJson.cs
- XPathChildIterator.cs
- FormDesigner.cs
- MetadataArtifactLoader.cs
- ToolStripItemImageRenderEventArgs.cs
- Misc.cs
- TablePatternIdentifiers.cs
- Triplet.cs
- TextBlock.cs
- TargetParameterCountException.cs
- TextTabProperties.cs
- TableColumn.cs
- BasicCellRelation.cs
- XPathPatternBuilder.cs
- AnnotationAuthorChangedEventArgs.cs
- WindowsAuthenticationModule.cs
- RelAssertionDirectKeyIdentifierClause.cs
- AnimatedTypeHelpers.cs
- SubMenuStyleCollection.cs
- CodeObjectCreateExpression.cs
- XamlDesignerSerializationManager.cs
- SocketStream.cs
- XmlAttributes.cs
- Geometry.cs
- XPathException.cs
- SelectionHighlightInfo.cs
- ConfigurationManagerInternalFactory.cs
- PerformanceCounterCategory.cs
- SortDescription.cs
- Polygon.cs
- SiteMapNode.cs
- WebPermission.cs
- IdentityNotMappedException.cs
- LayoutDump.cs
- _ChunkParse.cs
- StatusBarAutomationPeer.cs
- Label.cs
- Command.cs
- ServiceHostingEnvironment.cs
- ColumnTypeConverter.cs
- Binding.cs
- Soap12FormatExtensions.cs
- XAMLParseException.cs
- WindowsFormsHostPropertyMap.cs
- CustomErrorCollection.cs
- CompoundFileReference.cs
- FilterQuery.cs
- MouseEventArgs.cs
- METAHEADER.cs
- HttpValueCollection.cs
- QilList.cs
- CaretElement.cs
- CharAnimationUsingKeyFrames.cs
- CommandBindingCollection.cs
- Timer.cs
- WebPartAddingEventArgs.cs
- Span.cs
- Activator.cs
- Mapping.cs
- VisualBasicSettingsConverter.cs
- WebPartMovingEventArgs.cs
- RegexBoyerMoore.cs
- ExceptionTrace.cs