如何取消等待任务在C#中执行多个任务

时间:2018-08-30 03:58:46

标签: c# async-await cancellationtokensource cancellation-token

我在空闲时间有一定的功能,例如在一定的时间间隔每30秒就会对硬件进行一次轮询以获取状态。

该方法的名称为public static async Task PollCurrentHardwareStatus(),该名称在该方法内部,会通过每个硬件的状态,例如:我有4个设备来获取连接状态(打印机模块,现金模块,硬币模块,终端模块)。

如果在主屏幕上进行公共触摸,它将转移到下一个我需要取消民意调查状态的页面。如何在等待任务中取消设备的轮询状态?

我已经通过Cancel an Async Task or a List of Tasks (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 个答案:

答案 0 :(得分:2)

我认为您可以从调用PollCurrentHardwareStatus()的方法中创建CancellationTokenSource。请检查以下示例:

将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();
    }
}

答案 1 :(得分:0)

根据MSDN:Cancellation in managed threads

  

取消是协作的,不强加于侦听器。的   侦听器确定如何优雅地终止以响应   取消请求。

您将必须创建PollCurrentHardwareStatus的重载,该重载将CancellationToken对象作为输入。该功能应定期检查是否请求取消,并优雅地取消该功能。

这有几个问题:什么是规则?请求取消时该怎么办。

答案取决于您的要求。这取决于您是否应该在50毫秒内取消中断,还是取消可能需要一秒钟。例如,如果当操作员第一次触摸您的屏幕时您的过程被中断,则该操作员可能希望等待半秒钟才能响应屏幕。但是,如果每次操作员键入字母时您的过程都中断,那么取消一秒钟可能会很烦人。

因此,您应该多久检查一次取消的问题取决于用法。

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

如果您调用一个需要较长时间处理的函数,则会出现问题。最好的办法是将token传递给其他进程:

LongProcessingFunction(token);

另一个功能应该定期检查令牌。 优雅地取消取决于此。 如果您无法更改其他功能,则不能保证正确,快速地取消操作。

async-await对此没有帮助。程序员需要创建等待的函数来提供接受CancellationToken的版本。

您会发现所有可等待的基本功能(读/写文件,从数据库或互联网获取信息等)都具有接受CancellationToken的版本。

您可以启动一个线程并在请求取消时杀死该线程,但这非常危险,因为在杀死该线程时您不知道对象的状态。我不建议这样做。