2016-06-01 8 views
3

Gibt es in C# einen Weg, eine Methode aufzurufen, so dass die Methode abgebrochen wird, wenn die Methode zu lange dauert zur aufrufenden Methode? Ich denke, ich kann dies mit Threading tun, aber was ist, wenn Threading nicht benötigt wird?Eine Methode aufrufen und abbrechen und zur aufrufenden Methode zurückkehren, wenn sie zu lange dauert

Als Referenz ruft die Methode, die ich möglicherweise abbrechen/stoppen/abbrechen muss, die CorelDraw 15-API auf. Dies öffnet eine Instanz von CorelDraw und ich habe nicht wiederholbare Fehler in dieser Methode erhalten. Bedeutung, ich kann das gleiche Bild zweimal verarbeiten und einmal wird es einfrieren oder Fehler und das andere wird es nicht.

Die aktuelle Lösung für das Problem, das ich verwende, ist eine zweite Anwendung, die Process.Start(firstAppExecutablePath) tut und dann prüft eine Variable in einer Textdatei und wenn die Variable nicht nach 10 Minuten ändert, wird .Kill(); für die Instanz von aufgerufen der Prozess. Ich würde es vorziehen, diese Lösung möglichst zu vermeiden, da sie klobig und anfällig für Probleme ist. Da es .Kill(); läuft, ist es sehr chaotisch, wie Dinge schließen, aber im Allgemeinen kein Problem verursacht.

+4

Wenn es nicht mit Gewinde versehen ist, dann gibt es keine Möglichkeit, ein Timeout zu überprüfen, weil der ausführende Thread Ihre Methode ausgeführt wird. Es gibt nichts zu überprüfen "hat es zu lange gedauert?" – dman2306

+4

Ist Ihre API asynchron? Dafür ist ein CancellationToken zuständig. – Crowcoder

+1

Was macht die Methode? – Luaan

Antwort

0

Threading ist unbedingt erforderlich, es sei denn, Sie überprüfen das Timeout innerhalb der Funktion, was wahrscheinlich nicht der Fall ist. Also hier ist ein minimalistischer Ansatz mit Gewinden:

private static bool ExecuteWithTimeout(TimeSpan timeout, Action action) 
{ 
    Thread x = new Thread(() => { action(); }); 
    x.Start(); 

    if (!x.Join(timeout)) 
    { 
     x.Abort(); //Or Interrupt instead, if you use e.g. Thread.Sleep in your method 
     return false; 
    } 

    return true; 
} 
+3

Es wird nicht empfohlen, andere Threads abzubrechen.Wenn der andere Thread gerade einen statischen Konstruktor ausführt, riskiert man nie, ein Objekt des Typs mit diesem Konstruktor in diesem Prozess zu konstruieren. Siehe den Hinweis in [der Dokumentation] (https://msdn.microsoft.com/en-us/library/ty8d3wta (v = vs.110) .aspx # Anchor_2). –

+0

@Cameron 'x.Abort()' "löscht" es nicht und der Thread "macht glücklich weiter sein Ding"? Ich finde das schwer zu glauben ... –

+0

@ LasseV.Karlsen Yup, das wäre schlecht. Aus diesem Grund wäre (wenn wir wüssten, welche Art von Code OP versucht abzubrechen), etwas mit einem CancellationToken oder zumindest mit Interrupt anstelle von Abort vorzuziehen. –

1

Nicht eingebaut, nein, da beliebigen Code unterbrach nicht sicher durchgeführt werden kann (was ist, wenn es in der Mitte ist eine C-Bibliothek Funktion des Aufrufs (dh nicht unterstützt Ausnahmen), die gerade eine globale Sperre genommen hat und diese freigeben muss?).

Aber Sie können solche Unterstützung selbst schreiben. Ich würde der Mischung keine Threads hinzufügen, wenn sie nicht unbedingt notwendig sind, da sie eine ganze neue Dimension potentieller Probleme mit sich bringen.

Beispiel:

void Caller() 
{ 
    int result; 
    if (TryDoSomething(out result, 100)) { 
     System.Console.WriteLine("Result: {0}", result); 
    } 
} 

bool TryDoSomething(out int result, int timeoutMillis) 
{ 
    var sw = Stopwatch.StartNew(); 
    result = 0x12345678; 
    for (int i = 0; i != 100000000; ++i) { 
     if (sw.ElapsedMilliseconds > timeoutMillis) 
      return false; 
     result += i/(result % 43) + (i % 19); 
    } 
    return true; 
} 
+0

Das scheint die Frage nicht wirklich zu beantworten. Das OP möchte einen einzelnen Methodenaufruf zum Zeitlimit, während Sie eine einzelne kurze Operation für eine bestimmte Zeit wiederholen. Aus meiner Sicht nicht dasselbe (auch wenn OP sich vielleicht anders benimmt). – Chris

+0

@ Chris abgestimmt. Sie gehen davon aus, dass die Methode geändert werden kann, um zu überprüfen, wie lange sie ausgeführt wurde. Was passiert, wenn ich versuche, eine IO-Operation, die nur blockiert, zu unterbrechen? – dman2306

+0

'TryDoSomething' * ist * eine einzige Methode ;-) Die meisten Methoden können mit Checks für eine Zeitüberschreitung an strategischen Positionen ausgestattet werden. Die Schleife war nur ein Beispiel. Und ja, das setzt die Kontrolle über die Zielmethode voraus, die sich für das OP als nicht erwiesen erwiesen hat. Ich überlasse die Antwort für den allgemeinen Fall. E/A und andere Vorgänge auf Betriebssystemebene neigen dazu, nicht blockierende Versionen zu verwenden, die mit ausreichend Zeitaufwand in Timeouts integriert werden können. – Cameron