2

Ich habe eine kopflose UWP-Anwendung, die eine externe Bibliothek verwendet, um eine Verbindung zu einem seriellen Gerät herzustellen und einige Befehle zu senden. Es läuft eine Endlosschleife (wahr) mit einer 10-minütigen Pause zwischen den Schleifen. Der Messvorgang dauert ca. 4 Minuten. Die externe Bibliothek muss 3 Messungen ausführen und nach jedem Signal wird ein Ereignis ausgelöst. Wenn das Ereignis zum vierten Mal ausgelöst wird, weiß ich, dass ich die Ergebnisse zurückgeben kann.Abbrechen der asynchronen Methode, die Ereignisse aufruft

Nach 4 Stunden (+/- ein paar Sekunden) hört die Bibliothek auf, Ereignisse auszulösen (normalerweise löst sie das Ereignis ein oder zwei Mal aus und dann hält es an, keine Fehler, nichts).

Ich implementierte in DoMeasureAsync() unterhalb einer CancellationTokenSource, die die IsCancelled-Eigenschaft auf der TaskCompletionSource nach 8 Minuten festgelegt werden sollte, so dass die Aufgabe zurückgegeben und die Schleife fortgesetzt wird.

Problem: Wenn die Messung nicht abgeschlossen werden kann, ist die Aufgabe von nMeasureCompletionSource (die NMeasureCompletionSource nie in der Klasse CMeasure gesetzt sein Ergebnis bekommt) wird nie abgebrochen. Der in RespondToCancellationAsync() definierte Delegat sollte nach den acht Minuten ausgeführt werden.

Wenn die Messung ok läuft, kann ich in den Protokollen sehen, dass der Code in den

taskAtHand.ContinueWith((x) => 

     { 
      Logger.LogDebug("Disposing CancellationTokenSource..."); 
      cancellationTokenSource.Dispose(); 
     }); 

aufgerufen wird.

bearbeitet: Ist es möglich, dass der GC in nach den 4 Stunden kommt und freigibt vielleicht einige Variablen und tun macht so die App nicht in der Lage sein, die Befehle an den Sensor zu senden? - Es ist nicht der Fall

Was fehlt mir hier?

//this gets called in a while (true) loop 
    public Task<PMeasurement> DoMeasureAsync() 
    { 

     nMeasureCompletionSource = new TaskCompletionSource<PMeasurement>(); 

     cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(8)); 

     var t = cMeasure.Run(nitrateMeasureCompletionSource, cancellationTokenSource.Token); 

     var taskAtHand = nitrateMeasureCompletionSource.Task; 
     taskAtHand.ContinueWith((x) => 

     { 
      Logger.LogDebug("Disposing CancellationTokenSource..."); 
      cancellationTokenSource.Dispose(); 
     }); 

     return taskAtHand; 
    } 

    public class CMeasure 
    { 
     public async Task Run(TaskCompletionSource<PMeasurement> tcs, CancellationToken cancellationToken) 
     { 
      try 
      { 
       NMeasureCompletionSource = tcs; 
       CancellationToken = cancellationToken; 

       CancellationToken.Register(async() => await RespondToCancellationAsync(), useSynchronizationContext: false); 

       CloseDevice(); //Closing device if for some reason is still open 
       await Task.Delay(2500); 

       TheDevice = await GetDevice(); 

       measurementsdone = 0; 

       Process(); //start the first measurement 
      } 
      catch (Exception ex) 
      { 
       DisconnectCommManagerAndCloseDevice(); 

       NMeasureCompletionSource.SetException(ex); 
      } 
     } 

     public async Task RespondToCancellationAsync() 
     { 

      if (!NitrateMeasureCompletionSource.Task.IsCompleted) 
      { 
       Logger.LogDebug("Measure Completion Source is not completed. Cancelling..."); 
       NMeasureCompletionSource.SetCanceled(); 
      } 

      DisconnectCommManagerAndCloseDevice(); 

      await Task.Delay(2500); 

     } 

     private void Process() 
     { 

      if (measurementsdone < 3) 
      { 
       var message = Comm.Measure(m); //start a new measurement on the device 
      } 
      else 
      { 
       ... 
       NMeasureCompletionSource.SetResult(result); 
      } 

     } 

     //the method called when the event is raised by the external library 
     private void Comm_EndMeasurement(object sender, EventArgs e) 
     { 
      measurementsdone++; 

      Process(); 
     } 
    } 
+3

"Ist es möglich, dass der GC nach 4 Stunden kommt und vielleicht einige Variablen freigibt und die App dadurch nicht in der Lage ist, die Befehle an den Sensor zu senden?" - Wie kommst du zu dieser Hypothese? Stark referenzierte Objekte werden nicht von GC erfasst. Und selbst wenn dies der Fall wäre, sollten Sie einige Nullzeiger-Ausnahmen oder Ähnliches erhalten. – Fildor

+0

@Fildor in diesem Moment kann ich an alles denken :) –

+0

Oh, * das * verzweifelt ... in diesem Fall würde ich die dritte Partei isolieren und ihr Verhalten in einem Test-Projekt testen.Dieses Projekt würde nichts anderes tun, als "auf dem Gerät" zu verarbeiten und zu sehen, ob es den Callback auslöst. Und vielleicht die Roundtrip-Zeit messen. Wenn dies das gleiche Verhalten zeigt, werde ich den Hersteller kontaktieren und um Hilfe bitten. Wenn es in Ordnung und stabil läuft, dann würde ich etwas Mock erstellen, um es stattdessen von der dritten Partei zu verwenden, damit Sie das gesamte Design besser debuggen können. Oh, und verputzen Sie es mit Protokollierung. Sie können es später wieder entfernen, aber wenn Sie wirklich keine Ahnung haben, was passiert, lassen Sie den Code Ihnen sagen. – Fildor

Antwort

1

Nach weiteren Tests bin ich zu dem Schluss gekommen, dass es kein Speicherleck gibt und dass alle Objekte entsorgt werden. Die Stornierung funktioniert auch gut.

Bisher scheint es, dass mein Problem von der Ausführung der Headless-App auf dem Raspberry Pi kommt. Obwohl ich den Deferral = taskInstance.GetDeferral() verwende; es scheint, dass die Ausführung irgendwann gestoppt wird ...

Ich werde mehr testen und komme mit den Ergebnissen zurück (möglicherweise in einem neuen Post, aber ich werde auch hier einen Link setzen).

bearbeiten: Hier ist der neue Beitrag: UWP - Headless app stops after 3 or 4 hours

Edit 2: Das Problem aus einer Bibliothek 3rd-Party war, die ich nutzen musste und es hatte anders als eine Maden App aufgerufen werden . Intern erstellte es seinen eigenen TaskScheduler, wenn SynchronizationContext.Current null war.

Verwandte Themen