Thread.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Collections.Generic;
  5. using System.Diagnostics;
  6. using System.Diagnostics.CodeAnalysis;
  7. using System.Globalization;
  8. using System.Runtime.ConstrainedExecution;
  9. using System.Security.Principal;
  10. namespace System.Threading
  11. {
  12. public sealed partial class Thread : CriticalFinalizerObject
  13. {
  14. private static AsyncLocal<IPrincipal?>? s_asyncLocalPrincipal;
  15. [ThreadStatic]
  16. private static Thread? t_currentThread;
  17. public Thread(ThreadStart start)
  18. : this()
  19. {
  20. if (start == null)
  21. {
  22. throw new ArgumentNullException(nameof(start));
  23. }
  24. Create(start);
  25. }
  26. public Thread(ThreadStart start, int maxStackSize)
  27. : this()
  28. {
  29. if (start == null)
  30. {
  31. throw new ArgumentNullException(nameof(start));
  32. }
  33. if (maxStackSize < 0)
  34. {
  35. throw new ArgumentOutOfRangeException(nameof(maxStackSize), SR.ArgumentOutOfRange_NeedNonNegNum);
  36. }
  37. Create(start, maxStackSize);
  38. }
  39. public Thread(ParameterizedThreadStart start)
  40. : this()
  41. {
  42. if (start == null)
  43. {
  44. throw new ArgumentNullException(nameof(start));
  45. }
  46. Create(start);
  47. }
  48. public Thread(ParameterizedThreadStart start, int maxStackSize)
  49. : this()
  50. {
  51. if (start == null)
  52. {
  53. throw new ArgumentNullException(nameof(start));
  54. }
  55. if (maxStackSize < 0)
  56. {
  57. throw new ArgumentOutOfRangeException(nameof(maxStackSize), SR.ArgumentOutOfRange_NeedNonNegNum);
  58. }
  59. Create(start, maxStackSize);
  60. }
  61. private void RequireCurrentThread()
  62. {
  63. if (this != CurrentThread)
  64. {
  65. throw new InvalidOperationException(SR.Thread_Operation_RequiresCurrentThread);
  66. }
  67. }
  68. private void SetCultureOnUnstartedThread(CultureInfo value, bool uiCulture)
  69. {
  70. if (value == null)
  71. {
  72. throw new ArgumentNullException(nameof(value));
  73. }
  74. if ((ThreadState & ThreadState.Unstarted) == 0)
  75. {
  76. throw new InvalidOperationException(SR.Thread_Operation_RequiresCurrentThread);
  77. }
  78. SetCultureOnUnstartedThreadNoCheck(value, uiCulture);
  79. }
  80. partial void ThreadNameChanged(string? value);
  81. public CultureInfo CurrentCulture
  82. {
  83. get
  84. {
  85. RequireCurrentThread();
  86. return CultureInfo.CurrentCulture;
  87. }
  88. set
  89. {
  90. if (this != CurrentThread)
  91. {
  92. SetCultureOnUnstartedThread(value, uiCulture: false);
  93. return;
  94. }
  95. CultureInfo.CurrentCulture = value;
  96. }
  97. }
  98. public CultureInfo CurrentUICulture
  99. {
  100. get
  101. {
  102. RequireCurrentThread();
  103. return CultureInfo.CurrentUICulture;
  104. }
  105. set
  106. {
  107. if (this != CurrentThread)
  108. {
  109. SetCultureOnUnstartedThread(value, uiCulture: true);
  110. return;
  111. }
  112. CultureInfo.CurrentUICulture = value;
  113. }
  114. }
  115. public static IPrincipal? CurrentPrincipal
  116. {
  117. get
  118. {
  119. if (s_asyncLocalPrincipal is null)
  120. {
  121. CurrentPrincipal = AppDomain.CurrentDomain.GetThreadPrincipal();
  122. }
  123. return s_asyncLocalPrincipal?.Value;
  124. }
  125. set
  126. {
  127. if (s_asyncLocalPrincipal is null)
  128. {
  129. if (value is null)
  130. {
  131. return;
  132. }
  133. Interlocked.CompareExchange(ref s_asyncLocalPrincipal, new AsyncLocal<IPrincipal?>(), null);
  134. }
  135. s_asyncLocalPrincipal.Value = value;
  136. }
  137. }
  138. public static Thread CurrentThread => t_currentThread ?? InitializeCurrentThread();
  139. public ExecutionContext? ExecutionContext => ExecutionContext.Capture();
  140. public string? Name
  141. {
  142. get => _name;
  143. set
  144. {
  145. lock (this)
  146. {
  147. if (_name != null)
  148. {
  149. throw new InvalidOperationException(SR.InvalidOperation_WriteOnce);
  150. }
  151. _name = value;
  152. ThreadNameChanged(value);
  153. }
  154. }
  155. }
  156. public void Abort()
  157. {
  158. throw new PlatformNotSupportedException(SR.PlatformNotSupported_ThreadAbort);
  159. }
  160. public void Abort(object? stateInfo)
  161. {
  162. throw new PlatformNotSupportedException(SR.PlatformNotSupported_ThreadAbort);
  163. }
  164. public static void ResetAbort()
  165. {
  166. throw new PlatformNotSupportedException(SR.PlatformNotSupported_ThreadAbort);
  167. }
  168. [Obsolete("Thread.Suspend has been deprecated. Please use other classes in System.Threading, such as Monitor, Mutex, Event, and Semaphore, to synchronize Threads or protect resources. https://go.microsoft.com/fwlink/?linkid=14202", false)]
  169. public void Suspend()
  170. {
  171. throw new PlatformNotSupportedException(SR.PlatformNotSupported_ThreadSuspend);
  172. }
  173. [Obsolete("Thread.Resume has been deprecated. Please use other classes in System.Threading, such as Monitor, Mutex, Event, and Semaphore, to synchronize Threads or protect resources. https://go.microsoft.com/fwlink/?linkid=14202", false)]
  174. public void Resume()
  175. {
  176. throw new PlatformNotSupportedException(SR.PlatformNotSupported_ThreadSuspend);
  177. }
  178. // Currently, no special handling is done for critical regions, and no special handling is necessary to ensure thread
  179. // affinity. If that changes, the relevant functions would instead need to delegate to RuntimeThread.
  180. public static void BeginCriticalRegion() { }
  181. public static void EndCriticalRegion() { }
  182. public static void BeginThreadAffinity() { }
  183. public static void EndThreadAffinity() { }
  184. public static LocalDataStoreSlot AllocateDataSlot() => LocalDataStore.AllocateSlot();
  185. public static LocalDataStoreSlot AllocateNamedDataSlot(string name) => LocalDataStore.AllocateNamedSlot(name);
  186. public static LocalDataStoreSlot GetNamedDataSlot(string name) => LocalDataStore.GetNamedSlot(name);
  187. public static void FreeNamedDataSlot(string name) => LocalDataStore.FreeNamedSlot(name);
  188. public static object? GetData(LocalDataStoreSlot slot) => LocalDataStore.GetData(slot);
  189. public static void SetData(LocalDataStoreSlot slot, object? data) => LocalDataStore.SetData(slot, data);
  190. [Obsolete("The ApartmentState property has been deprecated. Use GetApartmentState, SetApartmentState or TrySetApartmentState instead.", false)]
  191. public ApartmentState ApartmentState
  192. {
  193. get => GetApartmentState();
  194. set => TrySetApartmentState(value);
  195. }
  196. public void SetApartmentState(ApartmentState state)
  197. {
  198. if (!TrySetApartmentState(state))
  199. {
  200. throw GetApartmentStateChangeFailedException();
  201. }
  202. }
  203. public bool TrySetApartmentState(ApartmentState state)
  204. {
  205. switch (state)
  206. {
  207. case ApartmentState.STA:
  208. case ApartmentState.MTA:
  209. case ApartmentState.Unknown:
  210. break;
  211. default:
  212. throw new ArgumentOutOfRangeException(SR.ArgumentOutOfRange_Enum, nameof(state));
  213. }
  214. return TrySetApartmentStateUnchecked(state);
  215. }
  216. [Obsolete("Thread.GetCompressedStack is no longer supported. Please use the System.Threading.CompressedStack class")]
  217. public CompressedStack GetCompressedStack()
  218. {
  219. throw new InvalidOperationException(SR.Thread_GetSetCompressedStack_NotSupported);
  220. }
  221. [Obsolete("Thread.SetCompressedStack is no longer supported. Please use the System.Threading.CompressedStack class")]
  222. public void SetCompressedStack(CompressedStack stack)
  223. {
  224. throw new InvalidOperationException(SR.Thread_GetSetCompressedStack_NotSupported);
  225. }
  226. public static AppDomain GetDomain() => AppDomain.CurrentDomain;
  227. public static int GetDomainID() => 1;
  228. public override int GetHashCode() => ManagedThreadId;
  229. public void Join() => Join(-1);
  230. public bool Join(TimeSpan timeout) => Join(WaitHandle.ToTimeoutMilliseconds(timeout));
  231. public static void MemoryBarrier() => Interlocked.MemoryBarrier();
  232. public static void Sleep(TimeSpan timeout) => Sleep(WaitHandle.ToTimeoutMilliseconds(timeout));
  233. public static byte VolatileRead(ref byte address) => Volatile.Read(ref address);
  234. public static double VolatileRead(ref double address) => Volatile.Read(ref address);
  235. public static short VolatileRead(ref short address) => Volatile.Read(ref address);
  236. public static int VolatileRead(ref int address) => Volatile.Read(ref address);
  237. public static long VolatileRead(ref long address) => Volatile.Read(ref address);
  238. public static IntPtr VolatileRead(ref IntPtr address) => Volatile.Read(ref address);
  239. [return: NotNullIfNotNull("address")]
  240. public static object? VolatileRead(ref object? address) => Volatile.Read(ref address);
  241. [CLSCompliant(false)]
  242. public static sbyte VolatileRead(ref sbyte address) => Volatile.Read(ref address);
  243. public static float VolatileRead(ref float address) => Volatile.Read(ref address);
  244. [CLSCompliant(false)]
  245. public static ushort VolatileRead(ref ushort address) => Volatile.Read(ref address);
  246. [CLSCompliant(false)]
  247. public static uint VolatileRead(ref uint address) => Volatile.Read(ref address);
  248. [CLSCompliant(false)]
  249. public static ulong VolatileRead(ref ulong address) => Volatile.Read(ref address);
  250. [CLSCompliant(false)]
  251. public static UIntPtr VolatileRead(ref UIntPtr address) => Volatile.Read(ref address);
  252. public static void VolatileWrite(ref byte address, byte value) => Volatile.Write(ref address, value);
  253. public static void VolatileWrite(ref double address, double value) => Volatile.Write(ref address, value);
  254. public static void VolatileWrite(ref short address, short value) => Volatile.Write(ref address, value);
  255. public static void VolatileWrite(ref int address, int value) => Volatile.Write(ref address, value);
  256. public static void VolatileWrite(ref long address, long value) => Volatile.Write(ref address, value);
  257. public static void VolatileWrite(ref IntPtr address, IntPtr value) => Volatile.Write(ref address, value);
  258. public static void VolatileWrite([NotNullIfNotNull("value")] ref object? address, object? value) => Volatile.Write(ref address, value);
  259. [CLSCompliant(false)]
  260. public static void VolatileWrite(ref sbyte address, sbyte value) => Volatile.Write(ref address, value);
  261. public static void VolatileWrite(ref float address, float value) => Volatile.Write(ref address, value);
  262. [CLSCompliant(false)]
  263. public static void VolatileWrite(ref ushort address, ushort value) => Volatile.Write(ref address, value);
  264. [CLSCompliant(false)]
  265. public static void VolatileWrite(ref uint address, uint value) => Volatile.Write(ref address, value);
  266. [CLSCompliant(false)]
  267. public static void VolatileWrite(ref ulong address, ulong value) => Volatile.Write(ref address, value);
  268. [CLSCompliant(false)]
  269. public static void VolatileWrite(ref UIntPtr address, UIntPtr value) => Volatile.Write(ref address, value);
  270. /// <summary>
  271. /// Manages functionality required to support members of <see cref="Thread"/> dealing with thread-local data
  272. /// </summary>
  273. private static class LocalDataStore
  274. {
  275. private static Dictionary<string, LocalDataStoreSlot>? s_nameToSlotMap;
  276. public static LocalDataStoreSlot AllocateSlot()
  277. {
  278. return new LocalDataStoreSlot(new ThreadLocal<object?>());
  279. }
  280. private static Dictionary<string, LocalDataStoreSlot> EnsureNameToSlotMap()
  281. {
  282. Dictionary<string, LocalDataStoreSlot>? nameToSlotMap = s_nameToSlotMap;
  283. if (nameToSlotMap != null)
  284. {
  285. return nameToSlotMap;
  286. }
  287. nameToSlotMap = new Dictionary<string, LocalDataStoreSlot>();
  288. return Interlocked.CompareExchange(ref s_nameToSlotMap, nameToSlotMap, null) ?? nameToSlotMap;
  289. }
  290. public static LocalDataStoreSlot AllocateNamedSlot(string name)
  291. {
  292. LocalDataStoreSlot slot = AllocateSlot();
  293. Dictionary<string, LocalDataStoreSlot> nameToSlotMap = EnsureNameToSlotMap();
  294. lock (nameToSlotMap)
  295. {
  296. nameToSlotMap.Add(name, slot);
  297. }
  298. return slot;
  299. }
  300. public static LocalDataStoreSlot GetNamedSlot(string name)
  301. {
  302. Dictionary<string, LocalDataStoreSlot> nameToSlotMap = EnsureNameToSlotMap();
  303. lock (nameToSlotMap)
  304. {
  305. LocalDataStoreSlot? slot;
  306. if (!nameToSlotMap.TryGetValue(name, out slot))
  307. {
  308. slot = AllocateSlot();
  309. nameToSlotMap[name] = slot;
  310. }
  311. return slot;
  312. }
  313. }
  314. public static void FreeNamedSlot(string name)
  315. {
  316. Dictionary<string, LocalDataStoreSlot> nameToSlotMap = EnsureNameToSlotMap();
  317. lock (nameToSlotMap)
  318. {
  319. nameToSlotMap.Remove(name);
  320. }
  321. }
  322. private static ThreadLocal<object?> GetThreadLocal(LocalDataStoreSlot slot)
  323. {
  324. if (slot == null)
  325. {
  326. throw new ArgumentNullException(nameof(slot));
  327. }
  328. Debug.Assert(slot.Data != null);
  329. return slot.Data;
  330. }
  331. public static object? GetData(LocalDataStoreSlot slot)
  332. {
  333. return GetThreadLocal(slot).Value;
  334. }
  335. public static void SetData(LocalDataStoreSlot slot, object? value)
  336. {
  337. GetThreadLocal(slot).Value = value;
  338. }
  339. }
  340. }
  341. }