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();
}
}
"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
@Fildor in diesem Moment kann ich an alles denken :) –
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