所有线程的管理都是通过 Thread 类完成的,包括公共语言运行时创建的线程,以及进入托管环境以执行代码的运行时外部创建的线程。 运行时监视其进程中曾经在托管执行环境中执行代码的所有线程。 它不会跟踪任何其他线程。 线程可以通过 COM 互作进入托管执行环境(因为运行时将托管对象作为 COM 对象公开给非托管世界)、COM DllGetClassObject 函数和平台调用。
当非托管线程通过 COM 可调用包装器等方式进入运行时时,系统将检查该线程的线程本地存储以查找内部托管 Thread 对象。 如果找到一个,则运行时已知道此线程。 但是,如果找不到一个对象,运行时将生成一个新 Thread 对象,并将其安装在该线程的线程本地存储中。
在托管线程处理中, Thread.GetHashCode 是稳定的托管线程标识。 在线程的整个生命周期内,无论您是从哪个应用程序域获取这个值,它都不会与任何来自其他线程的值发生冲突。
从 Win32 线程处理到托管线程处理的映射
下表将 Win32 线程元素映射到其近似运行时等效项。 请注意,此映射并不表示相同的功能。 例如, TerminateThread 不执行 finally 子句或释放资源,并且无法阻止。 但 Thread.Abort 可以执行所有回滚代码,回收所有资源,并可以使用 ResetAbort来拒绝。 在对功能做出假设之前,请务必仔细阅读文档。
在 Win32 中 | 在公共语言运行时中 |
---|---|
CreateThread | 线程和ThreadStart的组合 |
TerminateThread | Thread.Abort |
SuspendThread | Thread.Suspend |
ResumeThread | Thread.Resume |
睡眠 | Thread.Sleep |
线程句柄上的WaitForSingleObject | Thread.Join |
ExitThread | 无等效项 |
GetCurrentThread (获取当前线程) | Thread.CurrentThread |
SetThreadPriority | Thread.Priority |
无等效项 | Thread.Name |
无等效项 | Thread.IsBackground |
接近 CoInitializeEx (OLE32.DLL) | Thread.ApartmentState |
托管线程和 COM 单元
可以标记托管线程以指示它将托管 单线程 或 多线程 单元。 (有关 COM 线程体系结构的详细信息,请参阅“进程”、“线程”和“单元”。GetApartmentState类的SetApartmentState和TrySetApartmentStateThread方法返回并分配线程的公寓状态。 如果未设置状态,GetApartmentState 返回 ApartmentState.Unknown。
仅当线程处于 ThreadState.Unstarted 状态时,才能设置该属性;该属性只能为线程设置一次。
如果在线程启动前未设置单元状态,则线程将初始化为多线程单元(MTA)。 终结器线程和所有由 ThreadPool 控制的线程都是 MTA。
重要
对于应用程序启动代码,控制单元状态的唯一方式是将 MTAThreadAttribute 或 STAThreadAttribute 应用于入口点过程。
向 COM 公开的托管对象的行为就如同它们聚合了自由线程封送拆收器一样。 换言之,它们可以通过自由线程的方式从任何 COM 单元中调用。 唯一不展示此自由线程行为的托管对象是那些从 ServicedComponent 或 StandardOleMarshalObject 派生的对象。
在托管领域中,不支持 SynchronizationAttribute ,除非使用上下文和上下文绑定的托管实例。 如果使用的是企业服务,则对象必须派生自 ServicedComponent (它本身派生自 ContextBoundObject)。
当托管代码调用 COM 对象时,它始终遵循 COM 规则。 换言之,它遵循 OLE32 的规定,通过 COM 单元代理和 COM+ 1.0 上下文包装来调用。
阻止问题
在阻止了非托管代码中的线程的操作系统中,如果线程进行非托管调用,则运行时将不会为 Thread.Interrupt 或 Thread.Abort控制该线程。 对于 Thread.Abort,运行时将该线程标记为 Abort ,并在重新进入托管代码时控制该线程。 使用托管阻止而不使用非托管阻止更为可取。 WaitHandle.WaitOne、WaitHandle.WaitAny、WaitHandle.WaitAll、Monitor.Enter、Monitor.TryEnter、Thread.Join、GC.WaitForPendingFinalizers等都响应Thread.Interrupt和Thread.Abort。 而且,如果你的线程处于单线程单元,则当你的线程被阻止时,单元中的所有托管阻止操作都将正确发送消息。
线程和光纤
.NET 线程模型不支持 光纤。 不应调用使用光纤实现的任何非托管函数。 此类调用可能会导致 .NET 运行时崩溃。