Enhanced C#
Language of your choice: library documentation
|
Provides access to a thread-local variable through a dictionary that maps thread IDs to values. More...
Provides access to a thread-local variable through a dictionary that maps thread IDs to values.
T | Type 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.
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] |
T | Value [get, set] |
Value of the thread-local variable. More... | |
T | 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; } |
T | _fallbackValue |
|
inline |
Constructs a ThreadLocalVariable.
initialValue | Initial 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. |
|
inline |
Constructs a ThreadLocalVariable.
initialValue | Initial value on the current thread. Does not affect other threads that are already running. |
fallbackValue | Value to use when a given thread doesn't have an associated value. |
propagator | A function that copies (and possibly modifies) the Value from a parent thread when starting a new thread. |
|
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.
|
getset |
Value of the thread-local variable.
This property returns FallbackValue if no value exists for this thread.