2010-02-15 31 views
34

ho oggetto obj che è terzo componente del partito,Impostare timeout per un'operazione

// this could take more than 30 seconds 
int result = obj.PerformInitTransaction(); 

Non so che cosa sta accadendo all'interno. Quello che so è se ci vuole più tempo, è fallito.

come impostare un meccanismo di timeout per questa operazione, in modo che se impiega più di 30 secondi, lancio semplicemente MoreThan30SecondsException?

risposta

66

È possibile eseguire l'operazione in un thread separato e poi mettere un timeout sul filo operazione di join:

using System.Threading; 

class Program { 
    static void DoSomething() { 
     try { 
      // your call here... 
      obj.PerformInitTransaction();   
     } catch (ThreadAbortException) { 
      // cleanup code, if needed... 
     } 
    } 

    public static void Main(params string[] args) { 

     Thread t = new Thread(DoSomething); 
     t.Start(); 
     if (!t.Join(TimeSpan.FromSeconds(30))) { 
      t.Abort(); 
      throw new Exception("More than 30 secs."); 
     } 
    } 
} 
+1

@Bomboca: I rollback la modifica, il 'Exception' sto buttando non dovrebbe essere un' ThreadAbortException', che è qualcosa gettato dal CLR quando una chiamata per 'Abort' è fatto. –

+0

scusami e grazie per l'input :) –

+2

È una chiamata bloccante, se hai bisogno del thread principale fai altre cose in questo momento non funzionerà! – feldeOne

1

Si potrebbe guardare richiamando il metodo in un thread e sul timeout, interrompere il filo e aumentare l'eccezione. Inoltre, in questo caso dovrai gestire l'eccezione ThreadBorted.

+0

Hai ragione riguardo a ThreadAbortedException, +1. –

0

C'è un bell'esempio di una soluzione generica a questo utilizzando una classe helper here.

Utilizza il delegato di azione per evitare la creazione/distruzione del thread mostrato nell'esempio precedente.

Spero che questo aiuti.

2

È necessario fare attenzione sull'annullamento di un'operazione come questa, specialmente perché si tratta di un componente di terze parti a cui non si ha (eventualmente) accesso al codice da modificare.

Se si interrompe l'operazione, non si saprà in quale stato si è lasciata la classe sottostante. Ad esempio, potrebbe aver acquisito un blocco e il vostro about ha causato il blocco di tale blocco. Anche se si distrugge l'oggetto dopo aver interrotto l'operazione, è possibile che abbia alterato uno stato a esso globale e pertanto non sarà possibile creare in modo affidabile una nuova istanza senza un riavvio.

6

Se non si desidera bloccare il thread principale è possibile utilizzare un System.Threading.Timer:

private Thread _thread; 

void Main(string[] args) 
{ 
    _thread = new ThreadStart(ThreadEntry); 
    _thread.Start(); 
    Timer timer = new Timer(Timeout,null,30000,Timeout.Infinite); 
} 


void ThreadEntry() 
{ 
    int result = obj.PerformInitTransaction(); 
} 

void TimeOut(object state) 
{ 
    // Abort the thread - see the comments 
    _thread.Abort(); 

    throw new ItTimedOutException(); 
} 

Jon Skeet ha un modo meno forte (Shutting Down Worker Threads Gracefully) di fermare il filo di abortire.

Tuttavia, poiché non si ha il controllo delle operazioni effettuate da PerformInitTransaction(), non c'è molto che si possa fare da quando Abort ha esito negativo e lascia l'oggetto in uno stato non valido. Come accennato se sei in grado di ripulire tutto ciò che ha interrotto lo PerformInitTransaction sospeso, puoi farlo catturando lo ThreadAbortException, anche se trattandosi di una chiamata di terze parti significherebbe indovinare lo stato in cui hai lasciato il loro metodo.

Il PerformInitTransaction dovrebbe essere quello che fornisce il timeout.

10

Più semplicemente utilizzando Task.Wait(TimeSpan):

using System.Threading.Tasks; 

var task = Task.Run(() => obj.PerformInitTransaction()); 
if (task.Wait(TimeSpan.FromSeconds(30))) 
    return task.Result; 
else 
    throw new Exception("Timed out"); 
+0

Questo è molto semplice e disponibile da .net 4.0. –

+0

Tuttavia, questo non ucciderà il thread –

Problemi correlati