Threading gestito e non gestito in Windows
Aggiornamento: novembre 2007
La gestione di tutti i thread viene realizzata attraverso la classe Thread, inclusi i thread creati da Common Language Runtime e quelli creati al di fuori dell'ambiente di esecuzione che entrano nell'ambiente gestito per eseguire il codice. L'ambiente di esecuzione monitora tutti i thread nel suo processo che hanno eseguito del codice all'interno dell'ambiente di esecuzione gestito e non tiene traccia di alcun altro thread. I thread possono entrare nell'ambiente di esecuzione gestito attraverso l'interoperabilità COM (dal momento che l'ambiente di esecuzione espone gli oggetti gestiti come oggetti COM al mondo non gestito), la funzione COM DllGetClassObject() e il richiamo della piattaforma.
Quando un thread non gestito entra nell'ambiente di esecuzione attraverso, ad esempio, un wrapper COM richiamabile, nell'archiviazione locale di thread viene eseguita la ricerca di un oggetto Thread gestito interno. Se ne viene trovato uno, all'ambiente di esecuzione è già nota la presenza di questo thread. Se non ne viene trovato alcuno, tuttavia, l'ambiente di esecuzione genera un nuovo oggetto Thread e lo installa nell'archivio del thread locale di quel thread.
Nel threading gestito il metodo Thread.GetHashCode restituisce una valida identificazione del thread gestito. Per la tutta la durata del thread, non entrerà in conflitto con il valore di un qualsiasi altro thread, indipendentemente dal dominio dell'applicazione per il quale si ottiene questo valore.
Nota: |
---|
Un ThreadId del sistema operativo non ha una relazione fissa con un thread gestito in quanto un host non gestito può controllare la relazione tra thread gestiti e non gestiti. In particolare, un host sofisticato può utilizzare l'API del fiber per pianificare molti thread gestiti sul thread dello stesso sistema operativo o per spostare un thread gestito tra thread di diversi sistemi operativi. |
Mapping dal threading Win32 al threading gestito
Nella tabella che segue vengono mostrati gli elementi del threading Win32 e i corrispondenti elementi del threading gestito. Queste corrispondenze non implicano una funzionalità completamente identica. TerminateThread, ad esempio, non esegue le clausole finally né libera risorse e non può essere impedito. Tuttavia, Thread.Abort consente di eseguire tutto il codice di rollback e recuperare tutte le risorse e può essere inibito utilizzando ResetAbort. Leggere con attenzione la documentazione per utilizzare correttamente la funzionalità.
In Win32 |
In Common Language Runtime |
---|---|
CreateThread |
Combinazione di Thread e ThreadStart. |
TerminateThread |
|
SuspendThread |
|
ResumeThread |
|
Sleep |
|
WaitForSingleObject sull'handle del thread |
|
ExitThread |
Nessun equivalente |
GetCurrentThread |
|
SetThreadPriority |
|
Nessun equivalente |
|
Nessun equivalente |
|
Vicino a CoInitializeEx (OLE32.DLL) |
Thread gestiti e di tipo Apartment COM
Un thread gestito può essere contrassegnato per indicare che ospiterà apartment a thread singolo o a thread multipli. I metodi GetApartmentState, SetApartmentState e TrySetApartmentState della classe Thread restituiscono e assegnano lo stato apartment di un thread. Se lo stato non è impostato, GetApartmentState restituisce ApartmentState.Unknown.
Nota: |
---|
In .NET Framework versioni 1.0 e 1.1 la proprietà ApartmentState viene utilizzata per ottenere e impostare lo stato apartment. |
La proprietà può essere impostata solo quando il thread si trova nello stato ThreadState.Unstarted, ma solo una volta per thread.
Se lo stato apartment è impostato prima dell'avvio del thread, quest'ultimo viene inizializzato come MTA (Multi-Threaded Apartment). Il thread finalizzatore e tutti i thread controllati da ThreadPool sono di tipo MTA.
Nota importante: |
---|
Per il codice di avvio di applicazioni, il solo modo per controllare lo stato apartment consiste nell'applicare l'attributo MTAThreadAttribute o STAThreadAttribute alla routine del punto di ingresso. In .NET Framework versioni 1.0 e 1.1 la proprietà ApartmentState può essere impostata come prima riga del codice. Questa operazione non è consentita in .NET Framework versione 2.0. |
Gli oggetti gestiti esposti a COM si comportano come se avessero aggregato il gestore del marshalling con modello di threading Free. In altre parole, possono essere chiamati da qualsiasi apartment COM in una modalità di threading Free. Gli unici oggetti gestiti che non manifestano tale comportamento del modello di threading Free sono quelli che derivano da ServicedComponent.
Nell'ambiente gestito non è disponibile il supporto per SynchronizationAttribute a meno che non si utilizzino contesti e istanze legate al contesto. Se si utilizza EnterpriseServices, l'oggetto dovrà derivare da ServicedComponent, che a sua volta deriva da ContextBoundObject.
Quando il codice gestito effettua una chiamata agli oggetti COM, segue sempre le regole COM. In altre parole, chiama i proxy dell'apartment COM e i wrapper del contesto COM+ 1.0 come viene indicato da OLE32.
Problemi di blocco
Se un thread effettua una chiamata non gestita all'interno del sistema operativo che ha bloccato il thread nel codice non gestito, Common Language Runtime non ne assumerà il controllo per Thread.Interrupt o Thread.Abort. Nel caso di Thread.Abort, Common Language Runtime contrassegnerà il thread per Abort e ne assumerà il controllo al rientro nel codice gestito. È preferibile utilizzare il blocco gestito anziché quello non gestito. WaitHandle.WaitOne,WaitHandle.WaitAny, WaitHandle.WaitAll, Monitor.Enter, Monitor.TryEnter, Thread.Join, GC.WaitForPendingFinalizers e così via rispondono tutti a Thread.Interrupt e a Thread.Abort. Inoltre, se il thread è incluso in un apartment a thread singolo, tutte queste operazioni di blocco gestite eseguiranno correttamente il pumping dei messaggi nell'apartment finché il thread rimane bloccato.