所有線程的管理都是透過 Thread 類別完成,包括 Common Language Runtime 所建立的線程,以及在運行時間外部建立的線程,以進入 Managed 環境來執行程式代碼。 運行時間會監視其程序中曾經在受控執行環境中執行程式碼的所有執行緒。 它不會追蹤任何其他線程。 執行緒可以透過 COM Interop 進入受控的執行環境(因為執行時間會將受控物件公開為非受控世界的 COM 物件)、COM DllGetClassObject 函數和平台互操作。
當非受控執行緒透過例如 COM 可呼叫包裝器進入運行時,系統會檢查該執行緒的執行緒本地存儲,以尋找內部受控 Thread 物件。 如果找到其中一個,執行階段就已經知道這個執行緒。 不過,如果找不到物件,運行時間會建置新的 Thread 物件,並將它安裝在該線程的線程本地存儲中。
在管理線程中,Thread.GetHashCode 是穩定的受管線程識別。 在您的線程存留期內,不論您從哪個應用程式域取得此值,它都不會與任何其他線程的值相衝突。
從 Win32 線程對應到 Managed 線程處理
下表將 Win32 執行緒元素對應至其大致上的執行階段等效項目。 請注意,此對應並不代表相同的功能。 例如, TerminateThread 不會執行 finally 子句或釋放資源,而且無法防止。 不過,Thread.Abort 會執行所有的復原程式碼,回收所有資源,並且可以使用 ResetAbort 來拒絕。 請務必先仔細閱讀文件,再假設功能。
| 在 Win32 中 | 在 Common Language Runtime(通用語言執行環境)中 |
|---|---|
| CreateThread | Thread和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 公寓模型
受控執行緒可以標記為表示其將裝載 單執行緒 或 多執行緒 Apartment。 (如需 COM 線程架構的詳細資訊,請參閱進程、線程和 Apartments。)類別GetApartmentState的 SetApartmentState 、 TrySetApartmentState和 Thread 方法會傳回並指派線程的 Apartment 狀態。 如果未設定狀態, GetApartmentState 則傳 ApartmentState.Unknown回 。
只有在線程處於 ThreadState.Unstarted 狀態時,才能設定 屬性;它只能針對線程設定一次。
如果在啟動線程之前未設定 Apartment 狀態,線程就會初始化為多線程 Apartment (MTA)。 最終化線程和由 ThreadPool 控制的所有線程都是 MTA。
這很重要
對於應用程式啟動代碼,控制 apartment 狀態的唯一方法是將 MTAThreadAttribute 或 STAThreadAttribute 套用至進入點程式。
公開給 COM 的 Managed 物件的行為就像已匯總自由線程封送器一樣。 換句話說,可以從任何 COM Apartment 以自由線程方式呼叫它們。 唯一不會顯示這種自由執行緒行為的受管理的物件,是那些從 ServicedComponent 或 StandardOleMarshalObject 衍生的物件。
在管理世界中,SynchronizationAttribute 不受支持,除非您使用上下文和上下文綁定的受控實例。 如果您使用企業服務,則您的對象必須衍生自 ServicedComponent (其本身衍生自 ContextBoundObject)。
當 Managed 程式代碼呼叫 COM 物件時,一律會遵循 COM 規則。 換句話說,它會透過 COM Apartment Proxy 和 COM+ 1.0 內容包裝函式呼叫,如 OLE32 所指示。
封鎖問題
如果一個線程在 Unmanaged 程式碼中被封鎖,並對作業系統進行 Unmanaged 呼叫,運行時將不會控制 Thread.Interrupt 或 Thread.Abort。 在 Thread.Abort 的情況下,執行環境會將線程標示為 中止,並在重新進入托管代碼時控制它。 最好是使用 Managed 封鎖,而不是 Unmanaged 封鎖。 WaitHandle.WaitOne、WaitHandle.WaitAny、 WaitHandle.WaitAll、 Monitor.Enter、 Monitor.TryEnter、 Thread.Join、 GC.WaitForPendingFinalizers等都回應 Thread.Interrupt 和 Thread.Abort。 此外,如果您的線程位於單個線程 Apartment 中,則當線程遭到封鎖時,所有這些受控封鎖作業都會正確地在 Apartment 中提取訊息。
線程和光纖
.NET 線程模型不支援 Fiber。 您不應該呼叫任何使用纖維實作的非管理函式。 這類呼叫可能會導致 .NET 運行時間當機。