Threading gestito e non gestito in Windows
La gestione di tutti i thread viene eseguita tramite la classe Thread , inclusi i thread creati da Common Language Runtime e quelli creati all'esterno dell'ambiente di esecuzione che accedono all'ambiente gestito per eseguire il codice. L'ambiente di esecuzione monitora tutti i thread nei relativi processi che abbiano eseguito codice nell'ambiente di esecuzione gestito. Non tiene traccia di altri thread. I thread possono accedere all'ambiente di esecuzione gestito tramite l'interoperabilità COM (perché il runtime espone gli oggetti gestiti come oggetti COM all'ambiente non gestito), la funzione DllGetClassObject COM e la funzionalità platform invoke.
Quando un thread non gestito accede al runtime tramite, ad esempio, un oggetto COM Callable Wrapper, il sistema verifica l'archivio locale dei thread del thread in questione per trovare un oggetto Thread gestito interno. Se ne viene trovato uno, all'ambiente di esecuzione è già nota la presenza di questo thread. Se non ne vengono trovati, tuttavia, il runtime compila un nuovo oggetto Thread e lo installa nell'archivio locale dei thread del thread in questione.
Nel threading gestito, Thread.GetHashCode rappresenta l'identificazione del thread gestito stabile. Per la durata del thread, questo non entrerà in conflitto con il valore di altri thread, indipendentemente dal dominio dell'applicazione da cui si è ottenuto il valore.
Mapping dal threading di Win32 al threading gestito
Nella tabella seguente viene mostrata la corrispondenza degli elementi del threading di Win32 con gli elementi equivalenti dell'ambiente di esecuzione. Si noti che questa corrispondenza non rappresenta funzionalità identiche. Ad esempio, TerminateThread non esegue clausole finally o libera risorse e non può essere evitato. Tuttavia, Thread.Abort esegue tutto il codice di ripristino dello stato precedente, recupera tutte le risorse e può essere negato tramite ResetAbort. Assicurarsi di leggere attentamente la documentazione prima di fare ipotesi sulle funzionalità.
Win32 | Common Language Runtime |
---|---|
CreateThread | Combinazione di Thread e ThreadStart |
TerminateThread | Thread.Abort |
SuspendThread | Thread.Suspend |
ResumeThread | Thread.Resume |
Sospensione | Thread.Sleep |
WaitForSingleObject sull'handle del thread | Thread.Join |
ExitThread | Nessun equivalente |
GetCurrentThread | Thread.CurrentThread |
SetThreadPriority | Thread.Priority |
Nessun equivalente | Thread.Name |
Nessun equivalente | Thread.IsBackground |
Chiudi su CoInitializeEx (OLE32.DLL) | Thread.ApartmentState |
Thread gestiti e apartment COM
Un thread gestito può essere contrassegnato per indicare che ospita un apartment a thread singolo o a thread multipli. Per altre informazioni sull'architettura di threading COM, vedere Processi, thread e apartment. I metodi GetApartmentState, SetApartmentState e TrySetApartmentState della classe Thread restituiscono e assegnano lo stato dell'apartment di un thread. Se lo stato non è stato impostato, GetApartmentState restituisce ApartmentState.Unknown.
La proprietà può essere impostata solo quando il thread è nello stato ThreadState.Unstarted e solo una volta per ogni thread.
Se lo stato dell'apartment non è impostato prima dell'avvio del thread, il thread viene inizializzato come un apartment a thread multipli. Il thread finalizzatore e tutti i thread controllati da ThreadPool sono apartment a thread multipli.
Importante
Per il codice di avvio dell'applicazione, l'unico modo per controllare lo stato dell'apartment consiste nell'applicare MTAThreadAttribute o STAThreadAttribute alla routine del punto di ingresso.
Gli oggetti gestiti esposti a COM si comportano come se avessero aggregato il gestore del marshalling a thread libero. In altre parole, possono essere chiamati da qualsiasi apartment COM con modello a thread libero. Gli unici oggetti gestiti che non esibiscono questo comportamento a thread libero sono gli oggetti che derivano da ServicedComponent o StandardOleMarshalObject.
Nell'ambiente gestito non è disponibile il supporto per SynchronizationAttribute a meno che non si usino i contesti e le istanze gestite associate al contesto. Se si usa Enterprise Services, l'oggetto deve derivare da ServicedComponent, che a sua volta è derivato da ContextBoundObject.
Quando il codice gestito effettua una chiamata agli oggetti COM, segue sempre le regole COM. In altre parole, la chiamata viene eseguita tramite proxy di apartment COM e wrapper del contesto COM+ 1.0 come indicato da OLE32.
Problemi che causano il blocco
Se un thread effettua una chiamata non gestita all'interno del sistema operativo che ha bloccato il thread nel codice non gestito, l'ambiente di esecuzione non ne assumerà il controllo per Thread.Interrupt o Thread.Abort. Nel caso di Thread.Abort, il runtime contrassegna il thread per Abort e ne assume il controllo al rientro nel codice gestito. È preferibile usare il blocco gestito anziché quello non gestito. WaitHandle.WaitOne,WaitHandle.WaitAny, WaitHandle.WaitAll, Monitor.Enter, Monitor.TryEnter, Thread.Join, GC.WaitForPendingFinalizers e così via sono tutti reattivi rispetto a Thread.Interrupt e 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 fintanto che il thread è bloccato.
Thread e fiber
Il modello di threading di .NET non supporta i fiber. Non chiamare una funzione non gestita implementata usando i fiber. Tali chiamate possono comportare un arresto anomalo del runtime .NET.