Отмена асинхронного метода, который вызывает события

У меня есть безголовое приложение 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();
        }
    }

1 ответ

После дополнительных испытаний я пришел к выводу, что утечки памяти нет и что все объекты уничтожены. Отмена работает также хорошо.

Пока что кажется, что моя проблема связана с запуском приложения без головы на Raspberry Pi. Хотя я использую deferral = taskInstance.GetDeferral(); кажется, что выполнение остановлено в некоторый момент...

Я протестирую больше и вернусь с результатами (возможно, в новом посте, но я также поставлю здесь ссылку).

Изменить: вот новое сообщение: UWP - приложение без головы останавливается через 3 или 4 часа

Изменить 2: Проблема была из сторонней библиотеки, которую я должен был использовать, и она должна была вызываться не так, как приложение без наушников. Внутренне он создавал свой собственный TaskScheduler, если SynchronizationContext.Current был нулевым.

Другие вопросы по тегам