Thread.cs 18 KB

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