2016-10-11 5 views
2

Ich weiß, dies ist nicht der erste Thread auf Cancelling Aufgaben, aber ich habe bisher nichts passendes gefunden, was meinen Bedürfnissen entspricht.C# UWP Abbrechen einer Aufgabe + Signalisierung Kind

Hier ist der Fall:

  • ich ein modulares System haben, in der Module durch eine Controller-Klasse initialisiert werden, wird dynamisch basierend auf Konfiguration.
  • Jedes Modul implementiert eine Connect() - Methode. Die Methode selbst ist ein Black-Box, aber für Hintergrundinformationen: einige Module versuchen, Bluetooth-Verbindungen zu erstellen.
  • Wenn die Verbindung zu lange dauert, möchte ich den Versuch abbrechen und in 5 Minuten wiederholen.

Zuerst legte ich die Wiederholungslogik in die Modulimplementierung. Das funktioniert gut, wird aber über Module repetitiv und gehört nicht wirklich zur Kernverantwortung des Moduls. Also überlegte ich, ob ich die Logik in den Controller einbauen sollte, aber ich habe Mühe, eine nette Implementierung zu finden.

Das Problem hier ist, dass ich nicht nur die Aufgabe abbrechen möchte, ich möchte es auf eine nette Art und Weise tun. Wenn Objekte zu schließen/zu entsorgen sind, sollte das Modul dazu in der Lage sein. Außerdem sollte das Modul in der Lage sein, seinen Status auf "Getrennt" anstatt auf "Verbinden" zu setzen (und ich möchte, dass das Modul dies tut als eine öffentliche Methode, um den Status extern zu ändern). Dies war alles einfach, wenn die Connect- und Timeout-Logik innerhalb des Moduls ist, aber es wird schwieriger, ein externes Timeout einzuführen.

Hier ist der Fluss sehe ich, wenn ein Modul nicht rechtzeitig reagiert:

  • -Controller eine Instanz neue Modul
  • -Controller ruft Connect(), um das Modul
  • -Controller auch initialisiert eine Verbindung erstellt ein Timer zur Überwachung des Moduls beendet den Anschluss in 30 Sekunden
  • Timer geht aus, Modul hat noch nicht seine Arbeit beendet
  • Connect() - Methode sollte von Cancel benachrichtigt werden B. durch Auslösen einer Ausnahme innerhalb der Connect-Methode, die gefangen und gehandhabt werden kann.
  • Exception-Handler kann dann Dinge sauber säubern und die Methode kehrt zurück.

Der obige Ablauf existiert nicht, soweit ich gefunden habe. Stornierungs-Token funktionieren anders und erfordern, dass Ereignisse oder Abfragen an Ort und Stelle sind. Das ist nett, aber dann bin ich wieder dabei, diese Logik in meine Module aufzunehmen, also warum nicht einfach das gesamte Retry-Ding machen, um damit anzufangen. Also frage ich mich, ob da draußen irgendein süßes Muster ist, das mir das erlaubt.

Ich baue übrigens für Windows 10 UWP. Ich habe keinen Code absichtlich hinzugefügt, weil das, was ich im Moment habe, sowieso Mist ist.

Antwort

1

Erhalten Sie nicht, was ist das Problem mit CancellationToken Ihre asynchrone Operation unterstützt die Stornierung oder gibt es keine Möglichkeit, den Code zu stoppen, der ausgeführt wird, es sei denn Sie den Thread oder Prozess beenden. Hier ist ein Beispiel für Timeout.

public static async Task Run() 
      { 
       var module = new Module(); 

       //No timeout 
       await module.Connect(1, CancelAfter(2000)); 

       try 
       { 
        // Timeout 
        await module.Connect(5, CancelAfter(1000)); 
       } 
       catch (Exception) 
       { 

        module.Dispose(); 
       } 

      } 

      public static CancellationToken CancelAfter(int millisecondsDelay) 
      { 
       var token = new CancellationTokenSource(); 
       token.CancelAfter(millisecondsDelay); 
       return token.Token; 
      } 

      public class Module : IDisposable 
      { 
       public async Task Connect(int count, CancellationToken cancel) 
       { 
        for (int i = 0; i < count; i++) 
        { 
         //This is just to simulte some work Task.Delay can be canceled as well with Task.Delay(500,cancel) 
         await Task.Delay(500); 
         cancel.ThrowIfCancellationRequested(); 
        } 
       } 

       public void Dispose() 
       { 

       } 
      } 

Sie können jede Aufgabe eine Zeitüberschreitung mit

public static class TaskTimeout 
    { 
     public static async Task TimeoutAfter(this Task task, int millisecondsTimeout) 
     { 
      if (task != await Task.WhenAny(task, Task.Delay(millisecondsTimeout))) 
      { throw new TimeoutException(); } 
     } 

     public static async Task<T> TimeoutAfter<T>(this Task<T> task, int millisecondsTimeout) 
     { 
      if (task != await Task.WhenAny(task, Task.Delay(millisecondsTimeout))) 
      { throw new TimeoutException(); } 
      else { return task.Result; } 
     } 
    } 

Aber dies wird nicht nur abbrechen, wenn Verbindung Connect kündbaren ist es abgebrochen werden kann. Die meisten Async-Aufrufe in .net haben CancellationToken implementiert, wenn Ihre Verbindung es verwendet.

+0

Genau das ist das Problem. My Connect() hat keine For- oder While-Schleife, in der ich das Token immer und immer wieder überprüfen kann. Es wird ein Verbindungsaufruf ausgelöst und dieser wartet, bis eine Verbindung besteht. Es ist dieser Anruf, den ich irgendwie töten muss, was ich im Moment mache, indem ich das Objekt von einem Timer-Ereignis entsorge. Es wäre viel schöner, wenn wir zu irgendeinem Zeitpunkt eine Laufzeitausnahme innerhalb der Connect() -Methode auslösen könnten. – Jasper

+0

Ich habe eine Bearbeitung vorgenommen, um zu sehen, wie Sie jede Aufgabe außer Kraft setzen können, aber Ihre Verfügung muss die Disposition übernehmen. –

Verwandte Themen