У меня есть безголовое приложение UWP, которое использует внешнюю библиотеку для подключения к последовательному устройству и отправки некоторых команд. Он запускает бесконечный цикл (пока это правда) с 10-минутной паузой между циклами. Процесс измерения занимает около 4 минут. Внешней библиотеке необходимо выполнить 3 измерения, и после каждого она подает сигнал, вызывая событие. Когда событие возникает в четвертый раз, я знаю, что могу вернуть результаты.
Через 4 часа (+/- несколько секунд) библиотека перестает поднимать события (обычно поднимает событие один или два раза, а потом останавливается, ни ошибок, ничего).
Я реализовал в DoMeasureAsync() ниже CancellationTokenSource, который должен был установить свойство IsCancelled в TaskCompletionSource через 8 минут, чтобы задача возвращалась и цикл продолжался.
Проблема: когда измерение не завершается (NMeasureCompletionSource никогда не получает набор результатов в классе CMeasure), задача из nMeasureCompletionSource никогда не отменяется. Делегат, определенный в RespondToCancellationAsync(), должен запуститься через 8 минут.
Если измерение проходит нормально, я вижу в журналах, что код в
taskAtHand.ContinueWith((x) =>
{
Logger.LogDebug("Disposing CancellationTokenSource...");
cancellationTokenSource.Dispose();
});
вызывается.
Изменить: Возможно ли, что GC приходит через 4 часа и, возможно, освобождает некоторые переменные, из-за чего приложение не может отправлять команды датчику? > - это не так
Что мне здесь не хватает?
//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();
}
}
ContinueWith
код сasync
/await
, и 3) убедиться, что все одноразовые предметы утилизированы (например,CancellationToken.Register
). - person Stephen Cleary   schedule 16.08.2017