Enhanced C#
Language of your choice: library documentation
Properties | Public Member Functions | Protected fields | List of all members
Loyc.Threading.ThreadLocalVariable< T > Class Template Reference

Provides access to a thread-local variable through a dictionary that maps thread IDs to values. More...


Source file:
Inheritance diagram for Loyc.Threading.ThreadLocalVariable< T >:
Loyc.Threading.ThreadLocalVariableBase

Remarks

Provides access to a thread-local variable through a dictionary that maps thread IDs to values.

Template Parameters
TType of variable to wrap

Note: this was written before .NET 4 (which has ThreadLocal{T}). Unlike ThreadLocal<T>, this class supports propagation from parent to child threads when used with ThreadEx.

This class exists to solve two problems. First, the [ThreadStatic] attribute is not supported in the .NET Compact Framework. Second, and more importantly, .NET does not propagate thread-local variables when creating new threads, which is a huge problem if you want to implement the Ambient Service Pattern. This class copies the T value from a parent thread to a child thread, but because .NET provides no way to hook into thread creation, it only works if you use ThreadEx instead of standard threads.

TODO: figure out how to support .NET's ExecutionContext

ThreadLocalVariable implements thread-local variables using a dictionary that maps thread IDs to values.

Variables of this type are typically static and they must NOT be marked with the [ThreadStatic] attribute.

ThreadLocalVariable(of T) is less convenient than the [ThreadStatic] attribute, but ThreadLocalVariable works with ThreadEx to propagate the value of the variable from parent threads to child threads, and you can install a propagator function to customize the way the variable is copied (e.g. in case you need a deep copy).

Despite my optimizations, ThreadLocalVariable is just over half as fast as a ThreadStatic variable in CLR 2.0, in a test with no thread contention. Access to the dictionary accounts for almost half of the execution time; try-finally (needed in case of asyncronous exceptions) blocks use up 11%; calling Thread.CurrentThread.ManagedThreadId takes about 9%; and the rest, I presume, is used up by the TinyReaderWriterLock.

TODO: consider switching from TinyReaderWriterLock+Dictionary to ConcurrentDictionary which has fine-grained locking (.NET 4 only).

Properties

bool HasValue [get]
 
Value [get, set]
 Value of the thread-local variable. More...
 
FallbackValue [get, set]
 When a thread is not created using ThreadEx, the value of your ThreadLocalVariable fails to propagate from the parent thread to the child thread. In that case, Value takes on the value of FallbackValue the first time it is called. More...
 

Public Member Functions

delegate TResult Func< TArg0, TResult > (TArg0 arg0)
 
 ThreadLocalVariable (T initialValue)
 Constructs a ThreadLocalVariable. More...
 
 ThreadLocalVariable (T initialValue, T fallbackValue, Func< T, T > propagator)
 Constructs a ThreadLocalVariable. More...
 

Protected fields

Dictionary< int, T > _tls = new Dictionary<int,T>(5)
 
TinyReaderWriterLock _lock = TinyReaderWriterLock.New
 
Func< T, T > _propagator = delegate(T v) { return v; }
 
_fallbackValue
 

Constructor & Destructor Documentation

Constructs a ThreadLocalVariable.

Parameters
initialValueInitial value on the current thread; also used as the FallbackValue in threads that are not created via ThreadEx and in other threads that are already running.
Loyc.Threading.ThreadLocalVariable< T >.ThreadLocalVariable ( initialValue,
fallbackValue,
Func< T, T >  propagator 
)
inline

Constructs a ThreadLocalVariable.

Parameters
initialValueInitial value on the current thread. Does not affect other threads that are already running.
fallbackValueValue to use when a given thread doesn't have an associated value.
propagatorA function that copies (and possibly modifies) the Value from a parent thread when starting a new thread.

Property Documentation

T Loyc.Threading.ThreadLocalVariable< T >.FallbackValue
getset

When a thread is not created using ThreadEx, the value of your ThreadLocalVariable fails to propagate from the parent thread to the child thread. In that case, Value takes on the value of FallbackValue the first time it is called.

By default, the FallbackValue is the initialValue passed to the constructor.

Value of the thread-local variable.

This property returns FallbackValue if no value exists for this thread.

Referenced by Loyc.MiniTest.Assert.Fail(), Loyc.MiniTest.Assert.Ignore(), Loyc.MiniTest.Assert.Inconclusive(), and Loyc.MiniTest.Assert.Success().