Thread.cs 15 KB

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