MDA asynchronousThreadAbort
Aggiornamento: novembre 2007
L'assistente al debug gestito asynchronousThreadAbort viene attivato quando un thread tenta di introdurre un'interruzione asincrona in un altro thread. L'MDA asynchronousThreadAbort non viene invece attivato da interruzioni sincrone dei thread.
Sintomi
Si verifica l'arresto anomalo di un'applicazione con la generazione di una ThreadAbortException non gestita quando viene interrotto il thread principale dell'applicazione. Se l'esecuzione dell'applicazione dovesse continuare, le conseguenze potrebbero essere peggiori di un arresto anomalo. Si potrebbe infatti verificare un ulteriore danneggiamento dei dati.
Con molta probabilità operazioni che dovevano essere atomiche sono state interrotte dopo il completamento parziale, lasciando i dati dell'applicazione in uno stato imprevedibile. È possibile che venga generata una ThreadAbortException da punti apparentemente causali nell'esecuzione del codice che spesso coincidono con posizioni in cui non è prevista la generazione di un'eccezione. Il codice può non essere in grado di gestire questo tipo di eccezioni e determinare in questo caso uno problema di danneggiamento.
I sintomi variano ampiamente a causa della casualità implicita nel problema.
Causa
Il codice presente in un thread ha chiamato il metodo Thread.Abort su un thread di destinazione per introdurre un'interruzione asincrona. L'interruzione è asincrona perché il codice che effettua la chiamata a Abort è in esecuzione su un thread diverso da quello di destinazione dell'operazione di interruzione. In genere, le interruzioni sincrone dei thread non causano problemi in quanto il thread che esegue il metodo Abort effettua tale operazione solo in un checkpoint sicuro in cui lo stato dell'applicazione è coerente.
Le interruzioni asincrone dei thread sono invece un problema in quanto vengono elaborate in punti imprevisti nell'esecuzione del thread di destinazione. Per evitare ciò, il codice scritto per essere eseguito su un thread che potrebbe essere interrotto in questo modo deve gestire almeno una ThreadAbortException per ogni riga, prestando attenzione a ripristinare lo stato di coerenza dei dati dell'applicazione. Tuttavia, non è realistico prevedere la scrittura di codice tenendo presente questo problema o la protezione da tutti possibili rischi.
Le chiamate a codice non gestito e a blocchi finally non vengono interrotte in modo asincrono, ma all'uscita da una di queste categorie.
Può essere difficile stabilire la causa del problema per via della sua causalità implicita.
Risoluzione
Evitare la progettazione di codice che richieda l'uso di interruzioni asincrone dei thread. Sono disponibili diversi approcci più adeguati per l'interruzione di un thread di destinazione che non richiedono una chiamata al metodo Abort. L'approccio più sicuro consiste nell'introduzione di un meccanismo, ad esempio una proprietà comune, che segnali al thread di destinazione di richiedere un'interruzione. Il thread di destinazione verificherà il segnale in determinati checkpoint sicuri e, in caso di rilevamento di una richiesta di interruzione, potrà eseguire la chiusura correttamente.
Effetto sul runtime
Questo assistente al debug gestito non produce effetti su CLR. Si limita a generare un report dei dati relativi alle interruzioni asincrone dei thread.
Output
L'assistente al debug gestito segnala l'ID del thread che esegue l'interruzione e l'ID del thread di destinazione dell'interruzione che non coincideranno mai, in quanto l'utilizzo di questo assistente è limitato alle sole interruzioni asincrone.
Configurazione
<mdaConfig>
<assistants>
<asynchronousThreadAbort />
</assistants>
</mdaConfig>
Esempio
L'attivazione dell'assistente al debug gestito asynchronousThreadAbort richiede una sola chiamata al metodo Abort su un altro thread in esecuzione. Considerare le conseguenze nel caso in cui il contenuto della funzione di avvio del thread corrispondesse a un insieme di operazioni più complesse che potrebbero essere interrotte in modo anomalo in un qualsiasi punto arbitrario.
using System.Threading;
void FireMda()
{
Thread t = new Thread(delegate() { Thread.Sleep(1000); });
t.Start();
// The following line activates the MDA.
t.Abort();
t.Join();
}
Vedere anche
Concetti
Diagnostica degli errori tramite gli assistenti al debug gestito