2009-06-10 9 views
7

Ho una discussione che si spegne e tenta di stabilire una connessione. Nel thread, effettuo una chiamata a una libreria di terze parti. A volte, questa chiamata si blocca e non ritorna mai. Sul thread dell'interfaccia utente, desidero essere in grado di annullare il tentativo di connessione interrompendo il thread, che dovrebbe interrompere la chiamata bloccata alla libreria di terze parti.Come gestisci un thread che ha una chiamata bloccata?

Ho chiamato Thread.Abort, ma ora ho letto che Thread.Abort funziona solo quando il controllo ritorna al codice gestito. Ho osservato che questo è vero, perché il thread non si interrompe mai, e sono stato seduto su Thread.Entra per dieci minuti adesso. Cosa dovrei fare con questo filo appeso? Dovrei semplicemente annullare il riferimento e andare avanti? Mi piacerebbe essere il più pulito possibile

risposta

3

Questa funzione nella libreria di terze parti non dispone di un timeout o funzione di annullare? Se è così, è un design piuttosto scadente. Non ci sarà nessuna soluzione carina qui, penso ...

Sfortunatamente, non c'è modo di aggirare il problema, a meno di usare l'API Win32 per uccidere il thread manualmente, che è certamente non sta per essere pulito. Tuttavia, se questa libreria di terze parti non ti offre altre opzioni, potrebbe essere la cosa giusta da fare. La funzione TerminateThread è ciò che vorresti usare, ma osserva l'avviso! Per ottenere l'ID del thread da passare a questa funzione, è necessario utilizzare un'altra chiamata API Win32 (la classe Thread non la espone direttamente). L'approccio qui sarà quello di impostare il valore di una variabile di classe volatile sul risultato di GetCurrentThreadId all'inizio del metodo di thread gestito e quindi utilizzare questo ID di thread in un secondo momento per terminare il thread.

4

Pensiero casuale: mi chiedo se potresti scrivere un secondo assembly come un piccolo exe di console che fa questa comunicazione ... lanciarlo con Process.Start e catturare i risultati tramite il file system o intercettando lo stdout. Quindi se si blocca puoi uccidere il processo.

Un po 'aspro, forse - e ovviamente ha le spese generali di generare un processo - ma dovrebbe essere almeno possibile ucciderlo.

+4

"Togli e nuke il sito dall'orbita: è l'unico modo per esserne sicuri." In effetti, tu sei corretto; questo è l'unico modo sicuro per terminare il codice di comportamento anomalo. Thread.Abort non è garantito per interrompere effettivamente il thread di comportamento anomalo; una discussione veramente maleducata può dirottare l'interruzione. Anche abbattere un appdomain non fa necessariamente quello che vuoi. Se si deve assolutamente, in modo positivo, uccidere codice con comportamenti scorretti, è necessario isolarlo in un processo eseguibile. –

+0

Grazie Ripley ... Voglio dire ... Eric ;-p (Avrei dato la risposta di Hudson, ma dovrei quindi usare gli strumenti del moderatore su me stesso ...) –

1

I thread gestiti non possono interrompere direttamente i thread nativi. Quindi, se la chiamata è bloccata nel codice nativo, il meglio che si può fare è avere il controllo del thread gestito e terminare una volta che ritorna. Se non ritorna mai, forse c'è una versione della chiamata con un timeout?

In caso contrario, uccidendo il filo (tramite win32) di solito non è una buona idea ...

+0

la chiamata non ritorna mai, ecco perché ho per terminare artificialmente il thread. – MedicineMan

2

Non so se questo lo farà o sarà accettabile, ma vale la pena provare.

[DllImport("kernel32.dll")] 
private static extern bool TerminateThread (Int32 id, Int32 dwexit); 

Dal documentation

TerminateThread è una funzione pericolosa che deve essere utilizzato solo nei casi più estremi. È necessario chiamare TerminateThread solo se si conosce esattamente cosa sta facendo il thread di destinazione e si controlla tutto il codice che il thread di destinazione potrebbe essere in esecuzione al momento della chiusura. Ad esempio, TerminateThread può causare i seguenti problemi:

  • Se il thread di destinazione possiede una sezione critica, la sezione critica non verrà rilasciata.
  • Se il thread di destinazione assegna memoria dall'heap, il blocco heap non verrà rilasciato.
  • Se il thread di destinazione esegue determinate chiamate kernel32 al termine, lo stato kernel32 per il processo del thread potrebbe essere incoerente.
  • Se il thread di destinazione sta manipolando lo stato globale di una DLL condivisa, lo stato della DLL potrebbe essere distrutto, interessando altri utenti della DLL.
-1

Non è una buona soluzione per mai attendere su un thread (in qualsiasi lingua) a tempo indeterminato, soprattutto se si stanno facendo chiamate esterne. Usa sempre un join con un timeout o uno spin lock che monitora lo stato di una variabile atomica condivisa finché non cambia, o raggiungi un timeout. Non sono un ragazzo di C#, ma queste sono tutte buone pratiche di concorrenza.

+0

hai letto anche la domanda –

+0

Sure fatto - grazie però. – Gandalf

Problemi correlati