2010-02-15 1 views
34

J'ai objet obj qui est le composant 3ème partie,Définir le délai d'une opération

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

Je ne sais pas ce qui se passe à l'intérieur. Ce que je sais, c'est que si cela prend plus de temps, c'est échoué.

comment configurer un mécanisme de délai pour cette opération, de sorte que si cela prend plus de 30 secondes, je viens de lancer MoreThan30SecondsException?

Répondre

66

Vous pouvez exécuter l'opération dans un thread séparé, puis mettre un délai d'attente sur le fil opération de jointure:

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: Je roulé en arrière votre édition, le 'Exception' je lance ne devrait pas être un' ThreadAbortException', ce qui est jeté par le CLR lors d'un appel à 'Abort' est fait. –

+0

désolé à ce sujet et merci pour l'entrée :) –

+2

C'est un appel bloquant, si vous avez besoin du fil principal faire d'autres choses à ce moment, cela ne fonctionnera pas! – feldeOne

1

Vous pouvez regarder d'appeler la méthode dans un fil et sur le délai d'attente, interrompre le fil et lever l'exception. En outre, vous devrez gérer l'exception ThreadBorted dans ce cas.

+0

Vous avez raison sur l'exception ThreadAbortedException, +1. –

0

Il existe un bel exemple de solution générique utilisant une classe auxiliaire here.

Il utilise le délégué Action pour éviter la création/destruction de threads illustrée dans l'exemple précédent.

J'espère que cela aide.

2

Vous devez faire attention à interrompre une opération comme celle-ci, d'autant plus que c'est dans un composant tiers que vous n'avez (éventuellement) pas accès au code à modifier.

Si vous annulez l'opération, vous ne saurez pas dans quel état vous avez laissé la classe sous-jacente. Par exemple, elle a peut-être acquis un verrou et votre sujet a provoqué la désactivation de ce verrou. Même si vous détruisez l'objet après l'annulation de l'opération, il peut avoir modifié un état qui lui est global et vous ne pourrez donc pas créer une nouvelle instance sans redémarrage de manière fiable.

6

Si vous ne voulez pas bloquer le thread principal vous pouvez utiliser 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 a une façon moins énergique (Shutting Down Worker Threads Gracefully) d'arrêter le fil que avorter.

Cependant, comme vous ne contrôlez pas les opérations effectuées par PerformInitTransaction(), vous ne pouvez pas faire grand-chose lorsque Abort échoue et laisse l'objet dans un état non valide. Comme mentionné précédemment, si vous êtes en mesure de nettoyer tout ce qui a abandonné le PerformInitTransaction, vous pouvez le faire en attrapant le ThreadAbortException, bien que ce soit un appel d'une tierce partie cela signifiera deviner l'état dans lequel vous avez laissé leur méthode.

Le PerformInitTransaction devrait vraiment être celui qui fournit le délai d'expiration.

10

Plus en utilisant simplement 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

Ceci est très simple et disponible depuis .net 4.0. –

+0

Cela ne va pas tuer le fil si –