Microsoft Windows 中的 Managed 和 Unmanaged 執行緒處理
更新:2007 年 11 月
所有執行緒的管理全都透過 Thread 類別進行,包括由 Common Language Runtime 建立的執行緒以及在 Runtime 之外建立,但進入 Managed 環境執行程式碼的執行緒。Runtime 會監視在其處理序中所有曾在 Managed 執行環境中執行程式碼的執行緒。它不會追蹤任何其他執行緒。執行緒可透過 COM Interop (因為執行階段會將 Managed 物件當做 COM 物件公開給 Unmanaged 外界)、COM DllGetClassObject() 函式和平台叫用 (Invoke) 進入 Managed 執行環境。
當 Unmanaged 執行緒透過類似 COM 可呼叫包裝函式進入執行階段時,系統會檢查這個執行緒的執行緒區域存放區,以尋找內部 Managed Thread 物件。如果找到的話,Runtime 就知道這個執行緒。不過,如果系統找不到執行緒,Runtime 會建置新的 Thread 物件並將它安裝在這個執行緒的執行緒本機存放區中。
在 Managed 執行緒處理中,Thread.GetHashCode 是穩定的 Managed 執行緒識別。就執行緒的存留期 (Lifetime) 而言,無論您是從哪一個應用程式定義域獲得這個值,執行緒的存留期都不會與任何其他執行緒發生衝突。
![]() |
---|
作業系統 ThreadId 與 Managed 執行緒之間沒有固定的關係,因為 Unmanaged 主應用程式可控制 Managed 和 Unmanaged 執行緒之間的關係。具體而言,精密的主機可使用 Fiber API 以依據同一作業系統執行緒來排程許多 Managed 執行緒,或是在不同作業系統執行緒之間移動 Managed 執行緒。 |
從 Win32 執行緒處理對應至 Managed 執行緒處理
下列表格將 Win32 執行緒處理項目對應至它們近似的執行階段對等項。請注意,此對應並不代表功能完全一樣。例如,TerminateThread 不執行 finally 子句或釋放資源,並且無法防止。然而,Thread.Abort 會執行所有的復原程式碼、回收所有資源,並且可使用 ResetAbort 加以拒絕。在設想功能之前,一定要仔細閱讀文件。
在 Win32 中 |
在 Common Language Runtime 中 |
---|---|
CreateThread |
Thread 和 ThreadStart 的組合 |
TerminateThread |
|
SuspendThread |
|
ResumeThread |
|
Sleep |
|
執行緒控制代碼上的 WaitForSingleObject |
|
ExitThread |
沒有對等用法 |
GetCurrentThread |
|
SetThreadPriority |
|
沒有對等用法 |
|
沒有對等用法 |
|
近似 CoInitializeEx (OLE32.DLL) |
Managed 執行緒和 COM Apartment
可標記 Managed 執行緒以指出它將裝載單一執行緒或多執行緒 Apartment。Thread 類別的 GetApartmentState、SetApartmentState 和 TrySetApartmentState 方法會傳回並指派執行緒的 Apartment 狀態。如果尚未設定此狀態,則 GetApartmentState 會傳回 ApartmentState.Unknown。
![]() |
---|
在 .NET Framework 1.0 和 1.1 版中,ApartmentState 屬性是用來取得及設定 Apartment 狀態。 |
只有當執行緒是處於 ThreadState.Unstarted 狀態時,才能設定此屬性;它只能針對執行緒設定一次。
如果在執行緒啟動之前就設定了 Apartment 狀態,則執行緒會初始化為多執行緒 Apartment (MTA)。受到 ThreadPool 控制的完成項執行緒及所有執行緒都是 MTA。
![]() |
---|
對於應用程式啟始程式碼 (Startup Code) 而言,控制 Apartment 狀態的唯一方法就是將 MTAThreadAttribute 或 STAThreadAttribute 套用到進入點程序。在 .NET Framework 1.0 和 1.1 版中,ApartmentState 屬性可設定為程式碼的第一行;而在 .NET Framework 2.0 版中不允許這樣的處理。 |
公開至 COM 的 Managed 物件看起來像是已彙總無限制執行緒封送處理器 (Free Threaded Marshaler)。換言之,可以無限制執行緒方式從任何 COM Apartment 呼叫 Managed 物件。只有衍生自 ServicedComponent 的 Managed 物件才不會表現出無限制執行緒行為。
在 Managed 世界中,除非您使用內容及內容繫結 Managed 執行個體,否則不支援 SynchronizationAttribute。如果您正在使用 EnterpriseServices,則您的物件必須衍生自 ServicedComponent (其本身係衍生自 ContextBoundObject)。
當 Managed 程式碼呼叫 COM 物件時,一定會遵循 COM 規則。換言之,它會按照 OLE32 的指示呼叫 COM Apartment Proxy 和 COM+ 1.0 內容包裝函式。
封鎖問題
如果執行緒對作業系統發出 Unmanaged 呼叫,而此呼叫在 Unmanaged 程式碼中封鎖了執行緒,則執行階段將不會針對 Thread.Interrupt 或 Thread.Abort 取得其控制權。如果是 Thread.Abort 的情況,則執行階段會為 Abort 標記執行緒,並在它重新進入 Managed 程式碼時取得其控制權。建議您使用 Managed 封鎖,而不要使用 Unmanaged 封鎖。WaitHandle.WaitOne、WaitHandle.WaitAny、WaitHandle.WaitAll、Monitor.Enter、Monitor.TryEnter、Thread.Join、GC.WaitForPendingFinalizers 等等,對於 Thread.Interrupt 和 Thread.Abort 都會有回應。此外,如果執行緒位在單一執行緒 Apartment 中,則當執行緒被封鎖時,所有這些 Managed 封鎖作業都會正確提取 Apartment 中的訊息。