mscorlib(4.0.0.0) API with additions
ThreadLocal.cs
2 using System.Diagnostics;
4 
5 namespace System.Threading
6 {
9  [DebuggerTypeProxy(typeof(SystemThreading_ThreadLocalDebugView<>))]
10  [DebuggerDisplay("IsValueCreated={IsValueCreated}, Value={ValueForDebugDisplay}, Count={ValuesCountForDebugDisplay}")]
11  [__DynamicallyInvokable]
12  [HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
13  public class ThreadLocal<T> : IDisposable
14  {
15  private struct LinkedSlotVolatile
16  {
17  internal volatile LinkedSlot Value;
18  }
19 
20  private sealed class LinkedSlot
21  {
22  internal volatile LinkedSlot Next;
23 
24  internal volatile LinkedSlot Previous;
25 
26  internal volatile LinkedSlotVolatile[] SlotArray;
27 
28  internal T Value;
29 
30  internal LinkedSlot(LinkedSlotVolatile[] slotArray)
31  {
32  SlotArray = slotArray;
33  }
34  }
35 
36  private class IdManager
37  {
38  private int m_nextIdToTry;
39 
40  private List<bool> m_freeIds = new List<bool>();
41 
42  internal int GetId()
43  {
44  lock (m_freeIds)
45  {
46  int i;
47  for (i = m_nextIdToTry; i < m_freeIds.Count && !m_freeIds[i]; i++)
48  {
49  }
50  if (i == m_freeIds.Count)
51  {
52  m_freeIds.Add(item: false);
53  }
54  else
55  {
56  m_freeIds[i] = false;
57  }
58  m_nextIdToTry = i + 1;
59  return i;
60  }
61  }
62 
63  internal void ReturnId(int id)
64  {
65  lock (m_freeIds)
66  {
67  m_freeIds[id] = true;
68  if (id < m_nextIdToTry)
69  {
70  m_nextIdToTry = id;
71  }
72  }
73  }
74  }
75 
76  private class FinalizationHelper
77  {
78  internal LinkedSlotVolatile[] SlotArray;
79 
80  private bool m_trackAllValues;
81 
82  internal FinalizationHelper(LinkedSlotVolatile[] slotArray, bool trackAllValues)
83  {
84  SlotArray = slotArray;
85  m_trackAllValues = trackAllValues;
86  }
87 
88  ~FinalizationHelper()
89  {
90  LinkedSlotVolatile[] slotArray = SlotArray;
91  int i = 0;
92  for (; i < slotArray.Length; i++)
93  {
94  LinkedSlot value = slotArray[i].Value;
95  if (value != null)
96  {
97  if (m_trackAllValues)
98  {
99  value.SlotArray = null;
100  }
101  else
102  {
103  lock (ThreadLocal<T>.s_idManager)
104  {
105  if (value.Next != null)
106  {
107  value.Next.Previous = value.Previous;
108  }
109  value.Previous.Next = value.Next;
110  }
111  }
112  }
113  }
114  }
115  }
116 
117  private Func<T> m_valueFactory;
118 
119  [ThreadStatic]
120  private static LinkedSlotVolatile[] ts_slotArray;
121 
122  [ThreadStatic]
123  private static FinalizationHelper ts_finalizationHelper;
124 
125  private int m_idComplement;
126 
127  private volatile bool m_initialized;
128 
129  private static IdManager s_idManager = new IdManager();
130 
131  private LinkedSlot m_linkedSlot = new LinkedSlot(null);
132 
133  private bool m_trackAllValues;
134 
140  [DebuggerBrowsable(DebuggerBrowsableState.Never)]
141  [__DynamicallyInvokable]
142  public T Value
143  {
144  [__DynamicallyInvokable]
145  get
146  {
147  LinkedSlotVolatile[] array = ts_slotArray;
148  int num = ~m_idComplement;
149  LinkedSlot value;
150  if (array != null && num >= 0 && num < array.Length && (value = array[num].Value) != null && m_initialized)
151  {
152  return value.Value;
153  }
154  return GetValueSlow();
155  }
156  [__DynamicallyInvokable]
157  set
158  {
159  LinkedSlotVolatile[] array = ts_slotArray;
160  int num = ~m_idComplement;
161  LinkedSlot value2;
162  if (array != null && num >= 0 && num < array.Length && (value2 = array[num].Value) != null && m_initialized)
163  {
164  value2.Value = value;
165  }
166  else
167  {
168  SetValueSlow(value, array);
169  }
170  }
171  }
172 
177  [__DynamicallyInvokable]
178  public IList<T> Values
179  {
180  [__DynamicallyInvokable]
181  get
182  {
183  if (!m_trackAllValues)
184  {
185  throw new InvalidOperationException(Environment.GetResourceString("ThreadLocal_ValuesNotAvailable"));
186  }
187  List<T> valuesAsList = GetValuesAsList();
188  if (valuesAsList == null)
189  {
190  throw new ObjectDisposedException(Environment.GetResourceString("ThreadLocal_Disposed"));
191  }
192  return valuesAsList;
193  }
194  }
195 
196  private int ValuesCountForDebugDisplay
197  {
198  get
199  {
200  int num = 0;
201  for (LinkedSlot next = m_linkedSlot.Next; next != null; next = next.Next)
202  {
203  num++;
204  }
205  return num;
206  }
207  }
208 
212  [__DynamicallyInvokable]
213  public bool IsValueCreated
214  {
215  [__DynamicallyInvokable]
216  get
217  {
218  int num = ~m_idComplement;
219  if (num < 0)
220  {
221  throw new ObjectDisposedException(Environment.GetResourceString("ThreadLocal_Disposed"));
222  }
223  LinkedSlotVolatile[] array = ts_slotArray;
224  if (array != null && num < array.Length)
225  {
226  return array[num].Value != null;
227  }
228  return false;
229  }
230  }
231 
232  internal T ValueForDebugDisplay
233  {
234  get
235  {
236  LinkedSlotVolatile[] array = ts_slotArray;
237  int num = ~m_idComplement;
238  LinkedSlot value;
239  if (array == null || num >= array.Length || (value = array[num].Value) == null || !m_initialized)
240  {
241  return default(T);
242  }
243  return value.Value;
244  }
245  }
246 
247  internal List<T> ValuesForDebugDisplay => GetValuesAsList();
248 
250  [__DynamicallyInvokable]
251  public ThreadLocal()
252  {
253  Initialize(null, trackAllValues: false);
254  }
255 
259  [__DynamicallyInvokable]
260  public ThreadLocal(bool trackAllValues)
261  {
262  Initialize(null, trackAllValues);
263  }
264 
269  [__DynamicallyInvokable]
270  public ThreadLocal(Func<T> valueFactory)
271  {
272  if (valueFactory == null)
273  {
274  throw new ArgumentNullException("valueFactory");
275  }
276  Initialize(valueFactory, trackAllValues: false);
277  }
278 
285  [__DynamicallyInvokable]
286  public ThreadLocal(Func<T> valueFactory, bool trackAllValues)
287  {
288  if (valueFactory == null)
289  {
290  throw new ArgumentNullException("valueFactory");
291  }
292  Initialize(valueFactory, trackAllValues);
293  }
294 
295  private void Initialize(Func<T> valueFactory, bool trackAllValues)
296  {
297  m_valueFactory = valueFactory;
298  m_trackAllValues = trackAllValues;
299  try
300  {
301  }
302  finally
303  {
304  m_idComplement = ~s_idManager.GetId();
305  m_initialized = true;
306  }
307  }
308 
310  [__DynamicallyInvokable]
311  ~ThreadLocal()
312  {
313  Dispose(disposing: false);
314  }
315 
317  [__DynamicallyInvokable]
318  public void Dispose()
319  {
320  Dispose(disposing: true);
321  GC.SuppressFinalize(this);
322  }
323 
326  [__DynamicallyInvokable]
327  protected virtual void Dispose(bool disposing)
328  {
329  int num;
330  lock (s_idManager)
331  {
332  num = ~m_idComplement;
333  m_idComplement = 0;
334  if (num < 0 || !m_initialized)
335  {
336  return;
337  }
338  m_initialized = false;
339  for (LinkedSlot next = m_linkedSlot.Next; next != null; next = next.Next)
340  {
341  LinkedSlotVolatile[] slotArray = next.SlotArray;
342  if (slotArray != null)
343  {
344  next.SlotArray = null;
345  slotArray[num].Value.Value = default(T);
346  slotArray[num].Value = null;
347  }
348  }
349  }
350  m_linkedSlot = null;
351  s_idManager.ReturnId(num);
352  }
353 
360  [__DynamicallyInvokable]
361  public override string ToString()
362  {
363  return Value.ToString();
364  }
365 
366  private T GetValueSlow()
367  {
368  int num = ~m_idComplement;
369  if (num < 0)
370  {
371  throw new ObjectDisposedException(Environment.GetResourceString("ThreadLocal_Disposed"));
372  }
374  T val;
375  if (m_valueFactory == null)
376  {
377  val = default(T);
378  }
379  else
380  {
381  val = m_valueFactory();
382  if (IsValueCreated)
383  {
384  throw new InvalidOperationException(Environment.GetResourceString("ThreadLocal_Value_RecursiveCallsToValue"));
385  }
386  }
387  Value = val;
388  return val;
389  }
390 
391  private void SetValueSlow(T value, LinkedSlotVolatile[] slotArray)
392  {
393  int num = ~m_idComplement;
394  if (num < 0)
395  {
396  throw new ObjectDisposedException(Environment.GetResourceString("ThreadLocal_Disposed"));
397  }
398  if (slotArray == null)
399  {
400  slotArray = new LinkedSlotVolatile[GetNewTableSize(num + 1)];
401  ts_finalizationHelper = new FinalizationHelper(slotArray, m_trackAllValues);
402  ts_slotArray = slotArray;
403  }
404  if (num >= slotArray.Length)
405  {
406  GrowTable(ref slotArray, num + 1);
407  ts_finalizationHelper.SlotArray = slotArray;
408  ts_slotArray = slotArray;
409  }
410  if (slotArray[num].Value == null)
411  {
412  CreateLinkedSlot(slotArray, num, value);
413  return;
414  }
415  LinkedSlot value2 = slotArray[num].Value;
416  if (!m_initialized)
417  {
418  throw new ObjectDisposedException(Environment.GetResourceString("ThreadLocal_Disposed"));
419  }
420  value2.Value = value;
421  }
422 
423  private void CreateLinkedSlot(LinkedSlotVolatile[] slotArray, int id, T value)
424  {
425  LinkedSlot linkedSlot = new LinkedSlot(slotArray);
426  lock (s_idManager)
427  {
428  if (!m_initialized)
429  {
430  throw new ObjectDisposedException(Environment.GetResourceString("ThreadLocal_Disposed"));
431  }
432  LinkedSlot linkedSlot2 = linkedSlot.Next = m_linkedSlot.Next;
433  linkedSlot.Previous = m_linkedSlot;
434  linkedSlot.Value = value;
435  if (linkedSlot2 != null)
436  {
437  linkedSlot2.Previous = linkedSlot;
438  }
439  m_linkedSlot.Next = linkedSlot;
440  slotArray[id].Value = linkedSlot;
441  }
442  }
443 
444  private List<T> GetValuesAsList()
445  {
446  List<T> list = new List<T>();
447  int num = ~m_idComplement;
448  if (num == -1)
449  {
450  return null;
451  }
452  for (LinkedSlot next = m_linkedSlot.Next; next != null; next = next.Next)
453  {
454  list.Add(next.Value);
455  }
456  return list;
457  }
458 
459  private void GrowTable(ref LinkedSlotVolatile[] table, int minLength)
460  {
461  int newTableSize = GetNewTableSize(minLength);
462  LinkedSlotVolatile[] array = new LinkedSlotVolatile[newTableSize];
463  lock (s_idManager)
464  {
465  for (int i = 0; i < table.Length; i++)
466  {
467  LinkedSlot value = table[i].Value;
468  if (value != null && value.SlotArray != null)
469  {
470  value.SlotArray = array;
471  array[i] = table[i];
472  }
473  }
474  }
475  table = array;
476  }
477 
478  private static int GetNewTableSize(int minSize)
479  {
480  if ((uint)minSize > 2146435071u)
481  {
482  return int.MaxValue;
483  }
484  int num = minSize - 1;
485  num |= num >> 1;
486  num |= num >> 2;
487  num |= num >> 4;
488  num |= num >> 8;
489  num |= num >> 16;
490  num++;
491  if ((uint)num > 2146435071u)
492  {
493  num = 2146435071;
494  }
495  return num;
496  }
497  }
498 }
The exception that is thrown when a null reference (Nothing in Visual Basic) is passed to a method th...
override string ToString()
Creates and returns a string representation of this instance for the current thread.
Definition: ThreadLocal.cs:361
T Value
Gets or sets the value of this instance for the current thread.
Definition: ThreadLocal.cs:143
int Count
Gets the number of elements contained in the T:System.Collections.Generic.List`1.
Definition: List.cs:296
static void SuppressFinalize(object obj)
Requests that the common language runtime not call the finalizer for the specified object.
Definition: GC.cs:308
ThreadLocal(Func< T > valueFactory)
Initializes the T:System.Threading.ThreadLocal`1 instance with the specified valueFactory function.
Definition: ThreadLocal.cs:270
ThreadLocal()
Initializes the T:System.Threading.ThreadLocal`1 instance.
Definition: ThreadLocal.cs:251
Provides a mechanism for releasing unmanaged resources.To browse the .NET Framework source code for t...
Definition: IDisposable.cs:8
Definition: __Canon.cs:3
The exception that is thrown when an operation is performed on a disposed object.
void Add(T item)
Adds an object to the end of the T:System.Collections.Generic.List`1.
Definition: List.cs:510
SecurityAction
Specifies the security actions that can be performed using declarative security.
Provides information about, and means to manipulate, the current environment and platform....
Definition: Environment.cs:21
Enables communication with a debugger. This class cannot be inherited.
Definition: Debugger.cs:11
Controls the system garbage collector, a service that automatically reclaims unused memory.
Definition: GC.cs:11
ThreadLocal(bool trackAllValues)
Initializes the T:System.Threading.ThreadLocal`1 instance and specifies whether all values are access...
Definition: ThreadLocal.cs:260
Provides thread-local storage of data.
Definition: ThreadLocal.cs:13
void Dispose()
Releases all resources used by the current instance of the T:System.Threading.ThreadLocal`1 class.
Definition: ThreadLocal.cs:318
Represents a collection of objects that can be individually accessed by index.
Definition: IList.cs:9
ThreadLocal(Func< T > valueFactory, bool trackAllValues)
Initializes the T:System.Threading.ThreadLocal`1 instance with the specified valueFactory function a...
Definition: ThreadLocal.cs:286
virtual void Dispose(bool disposing)
Releases the resources used by this T:System.Threading.ThreadLocal`1 instance.
Definition: ThreadLocal.cs:327
The exception that is thrown when a method call is invalid for the object's current state.
bool IsValueCreated
Gets whether P:System.Threading.ThreadLocal`1.Value is initialized on the current thread.
Definition: ThreadLocal.cs:214
static void NotifyOfCrossThreadDependency()
Notifies a debugger that execution is about to enter a path that involves a cross-thread dependency.
Definition: Debugger.cs:104
IList< T > Values
Gets a list for all of the values currently stored by all of the threads that have accessed this inst...
Definition: ThreadLocal.cs:179
DebuggerBrowsableState
Provides display instructions for the debugger.