Как отменить ожидание Задача, которая выполняет несколько задач в C#

У меня есть функция во время простоя, когда с определенным интервалом, например, каждые 30 секунд, он выполняет опрос аппаратного обеспечения на предмет статуса.

Имя метода public static async Task PollCurrentHardwareStatus() что внутри этого метода, он будет проходить через состояние каждого оборудования, например, у меня есть 4 устройства для получения статуса подключения (модуль принтера, кассовый модуль, модуль монеты, модуль терминала).

Если публичное прикосновение к главному экрану, оно переместится на следующую страницу, на которой мне нужно отменить статус опроса. Как отменить статус опроса устройства в Задаче ожидания?

Я прошел через Отменить асинхронную задачу или список задач (C#), но, похоже, не могу понять, куда поместить CancellationToken.

Мой код на PollCurrentHardwareStatus:-

public static async Task PollCurrentHardwareStatus()
{
    try
    {
        //POLLING CARD READER
        if (GlobVars.HwIDTech.Enabled)
        {
            if (IDTechDevice.PingForReply())
            {
                LogEvents($"[App] Terminal OK.", EventLogEntryType.Information);
                AppDeviceStatus.strIDTechStatus = StatusMessageIDTech.strSuccessID;
            }
            else
            {
                LogEvents($"[App] IDTechDevice: Not found/Disconnected", EventLogEntryType.Information);
                AppDeviceStatus.strIDTechStatus = StatusMessageIDTech.strErrorID;
            }
        }
        //POLLING PRINTER
        if (GlobVars.HwCustom.Enabled)
        {
            string description = string.Empty;
            int status = 0;
            PrintMain.PrinterGetStatus(ref description, ref status);
            if (status == 0)
            {
                AppDeviceStatus.strPrinterStatus = StatusMessagePrinter.strSuccessID;
            }
            else
            {
                LogEvents($"[App] Printer error: {description}", EventLogEntryType.Information);
                AppDeviceStatus.strPrinterStatus = StatusMessagePrinter.strErrorID;
            }
        }
        //POLLING CASH COIN MODULE
        if (GlobVars.HwB2B.Enabled && GlobVars.HwBCR.Enabled)
        {
            string B2BStatus = await CCMain.GetCurrentDeviceStatus();
            if (B2BStatus == "DISABLED")
            {
                AppDeviceStatus.strB2BStatus = StatusMessageB2B.strSuccessID;
                LogEvents($"[App] Poll B2B device: Status - OK.", EventLogEntryType.Information);
            }
            else
            {
                LogEvents($"[App] Poll B2B device: Status - {B2BStatus}.", EventLogEntryType.Information);
                AppDeviceStatus.strB2BStatus = StatusMessageB2B.strErrorID;
            }

            if (ModuleCoins.OpenConnection())
            {
                await ModuleCoins.PerformSelfTest();
                AppDeviceStatus.strBCRStatus = StatusMessageBCR.strSuccessID;
            }
            else
            {
                AppDeviceStatus.strBCRStatus = StatusMessageBCR.strErrorID;
            }
        }
        UpdateErrorStatus();
    }
    catch (Exception ex)
    {
        LogEvents($"[App] Poll hardware status : Ex-{ex.Message}. Stack Trace-{ex.StackTrace}", EventLogEntryType.Error);
    }
    await Task.Delay(100);
}

2 ответа

Я думаю, что вы можете создать CancellationTokenSource из метода, который вы вызываете PollCurrentHardwareStatus(). Пожалуйста, проверьте ниже пример:

Добавить CancellationTokenSource в качестве параметра в метод PollCurrentHardwareStatus

public static async Task PollCurrentHardwareStatus(CancellationToken cts)
    {
        // your logic code
        // ...............
    }

Создайте CancellationTokenSource и вызовите его в своем классе Page:

public class Page
{
    private CancellationTokenSource cancellationTokenSource;

    public Page()
    {
        cancellationTokenSource = new CancellationTokenSource();
    }

    public async void CallPoll()
    {
        await PollCurrentHardwareStatus(cancellationTokenSource.Token);
    }

    public void OnCancelPoll(object sender, EventArgs e)
    {
        cancellationTokenSource.Cancel();
    }
}

Согласно MSDN: отмена в управляемых потоках

Отмена является кооперативной и не навязывается слушателю. Слушатель определяет, как изящно завершить работу в ответ на запрос отмены.

Вам придется создать перегрузку PollCurrentHardwareStatus который принимает объект CancellationToken в качестве входных данных. Функция должна регулярно проверять, запрашивается ли отмена, и корректно отменять функцию.

В этом есть несколько проблем: что обычно? что делать при запросе отмены.

Ответы в соответствии с вашими требованиями. Это зависит от последовательности прерываний, которые вы должны были отменить в течение 50 мс, или от того, может ли отмена потребоваться секунда. Например, если ваш процесс прерывается, когда оператор впервые касается вашего экрана, этот оператор, возможно, пожелает подождать полсекунды, прежде чем экран откликнется. Но если ваш процесс прерывается каждый раз, когда оператор вводит букву, то одна секунда для отмены может раздражать.

Поэтому вопрос о том, как часто вы должны проверять отмену, зависит от использования.

async Task PollCurrentHardwareStatus(CancellatinToken token)
{
     token.ThrowIfCancellationRequested();
     DoSomeShortProcessing(); 
     token.ThrowIfCancellationRequested();
     DoSomeOtherProcessing();
     token.ThrowIfcancellationRequested();

и т.п.

Проблема возникает, если вы вызываете функцию, для обработки которой требуется больше времени. Лучше всего было бы передать token в другой процесс:

LongProcessingFunction(token);

Другая функция должна регулярно проверять токен. Изящно отмена зависит от этого. Если вы не можете изменить другую функцию, вы не можете гарантировать правильную и быструю отмену.

async-await не поможет вам в этом. Это программисты, которые создают ожидаемые функции для предоставления версий, которые принимают CancellationToken.

Вы обнаружите, что все основные ожидаемые функции (чтение / запись файла, получение информации из базы данных или Интернета и т. Д.) Имеют версию, которая принимает CancellationToken.

Вы можете запустить поток и убить этот поток при запросе отмены, но это довольно опасно, потому что вы не знаете состояние объекта, когда поток уничтожен. Я бы не советовал это.

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