Windows 中的托管和非托管线程处理

所有线程的管理都是通过 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类的SetApartmentStateTrySetApartmentStateThread方法返回并分配线程的公寓状态。 如果未设置状态,GetApartmentState 返回 ApartmentState.Unknown

仅当线程处于 ThreadState.Unstarted 状态时,才能设置该属性;该属性只能为线程设置一次。

如果在线程启动前未设置单元状态,则线程将初始化为多线程单元(MTA)。 终结器线程和所有由 ThreadPool 控制的线程都是 MTA。

重要

对于应用程序启动代码,控制单元状态的唯一方式是将 MTAThreadAttributeSTAThreadAttribute 应用于入口点过程。

向 COM 公开的托管对象的行为就如同它们聚合了自由线程封送拆收器一样。 换言之,它们可以通过自由线程的方式从任何 COM 单元中调用。 唯一不展示此自由线程行为的托管对象是那些从 ServicedComponentStandardOleMarshalObject 派生的对象。

在托管领域中,不支持 SynchronizationAttribute ,除非使用上下文和上下文绑定的托管实例。 如果使用的是企业服务,则对象必须派生自 ServicedComponent (它本身派生自 ContextBoundObject)。

当托管代码调用 COM 对象时,它始终遵循 COM 规则。 换言之,它遵循 OLE32 的规定,通过 COM 单元代理和 COM+ 1.0 上下文包装来调用。

阻止问题

在阻止了非托管代码中的线程的操作系统中,如果线程进行非托管调用,则运行时将不会为 Thread.InterruptThread.Abort控制该线程。 对于 Thread.Abort,运行时将该线程标记为 Abort ,并在重新进入托管代码时控制该线程。 使用托管阻止而不使用非托管阻止更为可取。 WaitHandle.WaitOneWaitHandle.WaitAnyWaitHandle.WaitAllMonitor.EnterMonitor.TryEnterThread.JoinGC.WaitForPendingFinalizers等都响应Thread.InterruptThread.Abort。 而且,如果你的线程处于单线程单元,则当你的线程被阻止时,单元中的所有托管阻止操作都将正确发送消息。

线程和光纤

.NET 线程模型不支持 光纤。 不应调用使用光纤实现的任何非托管函数。 此类调用可能会导致 .NET 运行时崩溃。

另请参阅