1
votes

I have a function at idle time when at certain interval e.g. every 30 seconds, it will perform a polling to hardware for status.

The method name is public static async Task PollCurrentHardwareStatus() which inside this method, it will go through status of every hardwares e.g. I have 4 devices to get connection status (printer module, cash module, coin module, terminal module).

If public touch on main screen, it will divert to next page which I need to cancel the poll status. How to cancel poll status of device in await Task?

I have come through Cancel an Async Task or a List of Tasks (C#) but I seems cannot get the idea where to put the CancellationToken.

My code at 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
How you call this method PollCurrentHardwareStatus() ?Nhan Phan
I'm calling from Page using await App.PollCurrentHardwareStatus();Luiey
@MohammadNikravesh that solution is running on single method which loop using while true. that solution is already applied on my socket listener. I'm posting after not find the solution at my situation. mostly the forum, blog only show single use. my situation is using more than one method to call and how to cancel the token at current hardware check and return. my question is not duplicate with others.\Luiey
@Luiey As I know you can use the same CancellationTokenSource for more than one thread and once you trig the token, It will send cancelation signal to all the threads which you passed the token, By the way hope to find your solution broMohammad Nikravesh
@MohammadNikravesh is it can be passing down to the sub method? I'm only using up to single method only which loop through while true. never know it can be passing to other thread using same CancellationTokenSource. =)Luiey

2 Answers

3
votes

I think you can create the CancellationTokenSource from the method which you are calling PollCurrentHardwareStatus(). Please check bellow example:

Add CancellationTokenSource as a parameter in PollCurrentHardwareStatus method

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

Create a CancellationTokenSource and call it on your Page class:

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
votes

According to MSDN: Cancellation in managed threads

Cancellation is cooperative and is not forced on the listener. The listener determines how to gracefully terminate in response to a cancellation request.

You'll have to create an overload of PollCurrentHardwareStatus that takes a CancellationToken object as input. The function should regularly check whether cancellation is requested and cancel the function gracefully.

There are several problems in this: what is reqularly? what to do when cancellation is requested.

The answers are up to your requirements. It depends on the kine of interruption on wether you should have cancelled within 50 msec, or whether the cancellation may take upon a second. For example, if your process is interrupted when a operator touches your screen for the first time, this operator might be wiling to wait half a second before the screen responds. But if your process is interrupted every time the operator types a letter, then one second to cancel might be annoying.

So the question how often you should check for cancellation depends on the usage.

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

etc.

The problem arises if you call a function that would take longer time to process. Best thing would be to pass the token to the other process:

LongProcessingFunction(token);

The other function should regularly check the token. Gracefully cancellation depends on this. If you can't change the other function, you can't guarantee proper and fast cancellation.

async-await does not help you in this. It is up to programmers who create awaitable functions to provide versions that accept a CancellationToken.

What you'll find is that all basic awaitable functions (Read / Write file, fetch information form a database or the internet, etc) have a version that accepts a CancellationToken.

You could start a Thread and kill this thread when cancellation is requested, but that is fairly dangerous, because you don't know the status of the object when the thread is killed. I would not advise that.