| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456 |
- // Licensed to the .NET Foundation under one or more agreements.
- // The .NET Foundation licenses this file to you under the MIT license.
- // See the LICENSE file in the project root for more information.
- using Internal.Runtime.Augments;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Globalization;
- using System.Runtime.ConstrainedExecution;
- using System.Security.Principal;
- namespace System.Threading
- {
- public sealed partial class Thread : CriticalFinalizerObject
- {
- [ThreadStatic]
- private static Thread t_currentThread;
- private static AsyncLocal<IPrincipal> s_asyncLocalPrincipal;
- private readonly RuntimeThread _runtimeThread;
- private Delegate _start;
- private CultureInfo _startCulture;
- private CultureInfo _startUICulture;
- private Thread(RuntimeThread runtimeThread)
- {
- Debug.Assert(runtimeThread != null);
- _runtimeThread = runtimeThread;
- }
- public Thread(ThreadStart start)
- {
- if (start == null)
- {
- throw new ArgumentNullException(nameof(start));
- }
- _runtimeThread = RuntimeThread.Create(ThreadMain_ThreadStart);
- Debug.Assert(_runtimeThread != null);
- _start = start;
- }
- public Thread(ThreadStart start, int maxStackSize)
- {
- if (start == null)
- {
- throw new ArgumentNullException(nameof(start));
- }
- if (maxStackSize < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(maxStackSize), SR.ArgumentOutOfRange_NeedNonnegativeNumber);
- }
- _runtimeThread = RuntimeThread.Create(ThreadMain_ThreadStart, maxStackSize);
- Debug.Assert(_runtimeThread != null);
- _start = start;
- }
- public Thread(ParameterizedThreadStart start)
- {
- if (start == null)
- {
- throw new ArgumentNullException(nameof(start));
- }
- _runtimeThread = RuntimeThread.Create(ThreadMain_ParameterizedThreadStart);
- Debug.Assert(_runtimeThread != null);
- _start = start;
- }
- public Thread(ParameterizedThreadStart start, int maxStackSize)
- {
- if (start == null)
- {
- throw new ArgumentNullException(nameof(start));
- }
- if (maxStackSize < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(maxStackSize), SR.ArgumentOutOfRange_NeedNonnegativeNumber);
- }
- _runtimeThread = RuntimeThread.Create(ThreadMain_ParameterizedThreadStart, maxStackSize);
- Debug.Assert(_runtimeThread != null);
- _start = start;
- }
- private Delegate InitializeNewThread()
- {
- t_currentThread = this;
- Delegate start = _start;
- _start = null;
- if (_startCulture != null)
- {
- CultureInfo.CurrentCulture = _startCulture;
- _startCulture = null;
- }
- if (_startUICulture != null)
- {
- CultureInfo.CurrentUICulture = _startUICulture;
- _startUICulture = null;
- }
- return start;
- }
- private void ThreadMain_ThreadStart()
- {
- ((ThreadStart)InitializeNewThread())();
- }
- private void ThreadMain_ParameterizedThreadStart(object parameter)
- {
- ((ParameterizedThreadStart)InitializeNewThread())(parameter);
- }
- public static Thread CurrentThread
- {
- get
- {
- Thread currentThread = t_currentThread;
- if (currentThread == null)
- {
- t_currentThread = currentThread = new Thread(RuntimeThread.CurrentThread);
- }
- return currentThread;
- }
- }
- private void RequireCurrentThread()
- {
- if (this != CurrentThread)
- {
- throw new InvalidOperationException(SR.Thread_Operation_RequiresCurrentThread);
- }
- }
- private void SetCultureOnUnstartedThread(CultureInfo value, ref CultureInfo culture)
- {
- if (value == null)
- {
- throw new ArgumentNullException(nameof(value));
- }
- if ((_runtimeThread.ThreadState & ThreadState.Unstarted) == 0)
- {
- throw new InvalidOperationException(SR.Thread_Operation_RequiresCurrentThread);
- }
- culture = value;
- }
- public CultureInfo CurrentCulture
- {
- get
- {
- RequireCurrentThread();
- return CultureInfo.CurrentCulture;
- }
- set
- {
- if (this != CurrentThread)
- {
- SetCultureOnUnstartedThread(value, ref _startCulture);
- return;
- }
- CultureInfo.CurrentCulture = value;
- }
- }
- public CultureInfo CurrentUICulture
- {
- get
- {
- RequireCurrentThread();
- return CultureInfo.CurrentUICulture;
- }
- set
- {
- if (this != CurrentThread)
- {
- SetCultureOnUnstartedThread(value, ref _startUICulture);
- return;
- }
- CultureInfo.CurrentUICulture = value;
- }
- }
- public static IPrincipal CurrentPrincipal
- {
- get
- {
- if (s_asyncLocalPrincipal is null)
- {
- CurrentPrincipal = AppDomain.CurrentDomain.GetThreadPrincipal();
- }
- return s_asyncLocalPrincipal?.Value;
- }
- set
- {
- if (s_asyncLocalPrincipal is null)
- {
- if (value is null)
- {
- return;
- }
- Interlocked.CompareExchange(ref s_asyncLocalPrincipal, new AsyncLocal<IPrincipal>(), null);
- }
- s_asyncLocalPrincipal.Value = value;
- }
- }
- public ExecutionContext ExecutionContext => ExecutionContext.Capture();
- public bool IsAlive => _runtimeThread.IsAlive;
- public bool IsBackground { get { return _runtimeThread.IsBackground; } set { _runtimeThread.IsBackground = value; } }
- public bool IsThreadPoolThread => _runtimeThread.IsThreadPoolThread;
- public int ManagedThreadId => _runtimeThread.ManagedThreadId;
- public string Name { get { return _runtimeThread.Name; } set { _runtimeThread.Name = value; } }
- public ThreadPriority Priority { get { return _runtimeThread.Priority; } set { _runtimeThread.Priority = value; } }
- public ThreadState ThreadState => _runtimeThread.ThreadState;
- public void Abort()
- {
- throw new PlatformNotSupportedException(SR.PlatformNotSupported_ThreadAbort);
- }
- public void Abort(object stateInfo)
- {
- throw new PlatformNotSupportedException(SR.PlatformNotSupported_ThreadAbort);
- }
- public static void ResetAbort()
- {
- throw new PlatformNotSupportedException(SR.PlatformNotSupported_ThreadAbort);
- }
- [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)]
- public void Suspend()
- {
- throw new PlatformNotSupportedException(SR.PlatformNotSupported_ThreadSuspend);
- }
- [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)]
- public void Resume()
- {
- throw new PlatformNotSupportedException(SR.PlatformNotSupported_ThreadSuspend);
- }
- // Currently, no special handling is done for critical regions, and no special handling is necessary to ensure thread
- // affinity. If that changes, the relevant functions would instead need to delegate to RuntimeThread.
- public static void BeginCriticalRegion() { }
- public static void EndCriticalRegion() { }
- public static void BeginThreadAffinity() { }
- public static void EndThreadAffinity() { }
- public static LocalDataStoreSlot AllocateDataSlot() => LocalDataStore.AllocateSlot();
- public static LocalDataStoreSlot AllocateNamedDataSlot(string name) => LocalDataStore.AllocateNamedSlot(name);
- public static LocalDataStoreSlot GetNamedDataSlot(string name) => LocalDataStore.GetNamedSlot(name);
- public static void FreeNamedDataSlot(string name) => LocalDataStore.FreeNamedSlot(name);
- public static object GetData(LocalDataStoreSlot slot) => LocalDataStore.GetData(slot);
- public static void SetData(LocalDataStoreSlot slot, object data) => LocalDataStore.SetData(slot, data);
- [Obsolete("The ApartmentState property has been deprecated. Use GetApartmentState, SetApartmentState or TrySetApartmentState instead.", false)]
- public ApartmentState ApartmentState
- {
- get
- {
- return GetApartmentState();
- }
- set
- {
- TrySetApartmentState(value);
- }
- }
- public void SetApartmentState(ApartmentState state)
- {
- if (!TrySetApartmentState(state))
- {
- throw GetApartmentStateChangeFailedException();
- }
- }
- public bool TrySetApartmentState(ApartmentState state)
- {
- switch (state)
- {
- case ApartmentState.STA:
- case ApartmentState.MTA:
- case ApartmentState.Unknown:
- break;
- default:
- throw new ArgumentOutOfRangeException(SR.ArgumentOutOfRange_Enum, nameof(state));
- }
- return TrySetApartmentStateUnchecked(state);
- }
- private static int ToTimeoutMilliseconds(TimeSpan timeout)
- {
- var timeoutMilliseconds = (long)timeout.TotalMilliseconds;
- if (timeoutMilliseconds < -1 || timeoutMilliseconds > int.MaxValue)
- {
- throw new ArgumentOutOfRangeException(nameof(timeout), SR.ArgumentOutOfRange_TimeoutMilliseconds);
- }
- return (int)timeoutMilliseconds;
- }
- [Obsolete("Thread.GetCompressedStack is no longer supported. Please use the System.Threading.CompressedStack class")]
- public CompressedStack GetCompressedStack()
- {
- throw new InvalidOperationException(SR.Thread_GetSetCompressedStack_NotSupported);
- }
- [Obsolete("Thread.SetCompressedStack is no longer supported. Please use the System.Threading.CompressedStack class")]
- public void SetCompressedStack(CompressedStack stack)
- {
- throw new InvalidOperationException(SR.Thread_GetSetCompressedStack_NotSupported);
- }
- public static int GetCurrentProcessorId() => RuntimeThread.GetCurrentProcessorId();
- public static AppDomain GetDomain() => AppDomain.CurrentDomain;
- public static int GetDomainID() => GetDomain().Id;
- public override int GetHashCode() => ManagedThreadId;
- public void Interrupt() => _runtimeThread.Interrupt();
- public void Join() => _runtimeThread.Join();
- public bool Join(int millisecondsTimeout) => _runtimeThread.Join(millisecondsTimeout);
- public bool Join(TimeSpan timeout) => Join(ToTimeoutMilliseconds(timeout));
- public static void MemoryBarrier() => Interlocked.MemoryBarrier();
- public static void Sleep(int millisecondsTimeout) => RuntimeThread.Sleep(millisecondsTimeout);
- public static void Sleep(TimeSpan timeout) => Sleep(ToTimeoutMilliseconds(timeout));
- public static void SpinWait(int iterations) => RuntimeThread.SpinWait(iterations);
- public static bool Yield() => RuntimeThread.Yield();
- public void Start() => _runtimeThread.Start();
- public void Start(object parameter) => _runtimeThread.Start(parameter);
- public static byte VolatileRead(ref byte address) => Volatile.Read(ref address);
- public static double VolatileRead(ref double address) => Volatile.Read(ref address);
- public static short VolatileRead(ref short address) => Volatile.Read(ref address);
- public static int VolatileRead(ref int address) => Volatile.Read(ref address);
- public static long VolatileRead(ref long address) => Volatile.Read(ref address);
- public static IntPtr VolatileRead(ref IntPtr address) => Volatile.Read(ref address);
- public static object VolatileRead(ref object address) => Volatile.Read(ref address);
- [CLSCompliant(false)]
- public static sbyte VolatileRead(ref sbyte address) => Volatile.Read(ref address);
- public static float VolatileRead(ref float address) => Volatile.Read(ref address);
- [CLSCompliant(false)]
- public static ushort VolatileRead(ref ushort address) => Volatile.Read(ref address);
- [CLSCompliant(false)]
- public static uint VolatileRead(ref uint address) => Volatile.Read(ref address);
- [CLSCompliant(false)]
- public static ulong VolatileRead(ref ulong address) => Volatile.Read(ref address);
- [CLSCompliant(false)]
- public static UIntPtr VolatileRead(ref UIntPtr address) => Volatile.Read(ref address);
- public static void VolatileWrite(ref byte address, byte value) => Volatile.Write(ref address, value);
- public static void VolatileWrite(ref double address, double value) => Volatile.Write(ref address, value);
- public static void VolatileWrite(ref short address, short value) => Volatile.Write(ref address, value);
- public static void VolatileWrite(ref int address, int value) => Volatile.Write(ref address, value);
- public static void VolatileWrite(ref long address, long value) => Volatile.Write(ref address, value);
- public static void VolatileWrite(ref IntPtr address, IntPtr value) => Volatile.Write(ref address, value);
- public static void VolatileWrite(ref object address, object value) => Volatile.Write(ref address, value);
- [CLSCompliant(false)]
- public static void VolatileWrite(ref sbyte address, sbyte value) => Volatile.Write(ref address, value);
- public static void VolatileWrite(ref float address, float value) => Volatile.Write(ref address, value);
- [CLSCompliant(false)]
- public static void VolatileWrite(ref ushort address, ushort value) => Volatile.Write(ref address, value);
- [CLSCompliant(false)]
- public static void VolatileWrite(ref uint address, uint value) => Volatile.Write(ref address, value);
- [CLSCompliant(false)]
- public static void VolatileWrite(ref ulong address, ulong value) => Volatile.Write(ref address, value);
- [CLSCompliant(false)]
- public static void VolatileWrite(ref UIntPtr address, UIntPtr value) => Volatile.Write(ref address, value);
- /// <summary>
- /// Manages functionality required to support members of <see cref="Thread"/> dealing with thread-local data
- /// </summary>
- private static class LocalDataStore
- {
- private static Dictionary<string, LocalDataStoreSlot> s_nameToSlotMap;
- public static LocalDataStoreSlot AllocateSlot()
- {
- return new LocalDataStoreSlot(new ThreadLocal<object>());
- }
- public static Dictionary<string, LocalDataStoreSlot> EnsureNameToSlotMap()
- {
- Dictionary<string, LocalDataStoreSlot> nameToSlotMap = s_nameToSlotMap;
- if (nameToSlotMap != null)
- {
- return nameToSlotMap;
- }
- nameToSlotMap = new Dictionary<string, LocalDataStoreSlot>();
- return Interlocked.CompareExchange(ref s_nameToSlotMap, nameToSlotMap, null) ?? nameToSlotMap;
- }
- public static LocalDataStoreSlot AllocateNamedSlot(string name)
- {
- LocalDataStoreSlot slot = AllocateSlot();
- Dictionary<string, LocalDataStoreSlot> nameToSlotMap = EnsureNameToSlotMap();
- lock (nameToSlotMap)
- {
- nameToSlotMap.Add(name, slot);
- }
- return slot;
- }
- public static LocalDataStoreSlot GetNamedSlot(string name)
- {
- Dictionary<string, LocalDataStoreSlot> nameToSlotMap = EnsureNameToSlotMap();
- lock (nameToSlotMap)
- {
- LocalDataStoreSlot slot;
- if (!nameToSlotMap.TryGetValue(name, out slot))
- {
- slot = AllocateSlot();
- nameToSlotMap[name] = slot;
- }
- return slot;
- }
- }
- public static void FreeNamedSlot(string name)
- {
- Dictionary<string, LocalDataStoreSlot> nameToSlotMap = EnsureNameToSlotMap();
- lock (nameToSlotMap)
- {
- nameToSlotMap.Remove(name);
- }
- }
- private static ThreadLocal<object> GetThreadLocal(LocalDataStoreSlot slot)
- {
- if (slot == null)
- {
- throw new ArgumentNullException(nameof(slot));
- }
- Debug.Assert(slot.Data != null);
- return slot.Data;
- }
- public static object GetData(LocalDataStoreSlot slot)
- {
- return GetThreadLocal(slot).Value;
- }
- public static void SetData(LocalDataStoreSlot slot, object value)
- {
- GetThreadLocal(slot).Value = value;
- }
- }
- }
- }
|