简体   繁体   中英

How to stop async Task after a certain period of time

I am trying to stop a task in C# after a certain period of time.

For my code: the Task.Delay().Wait() should just represent some work that the Task does.

My Code:

public static void Main()
{
    Console.WriteLine("starting app");
    try
    {
        Console.WriteLine("before");
        DoStuff(1000);
        Console.WriteLine("after");
    }
    catch
    {
        Console.WriteLine("TIMEOUT");
    }
    Console.WriteLine("Main finished wait 5 sec now");
    Task.Delay(10000).Wait();
    Console.WriteLine("Closing app now");
}

public static async Task DoStuff(int time)
{
    Task real = Task.Run(()=>
    {
        Task.Delay(2000).Wait();
        Console.WriteLine("Task Running");
        Task.Delay(2000).Wait();
        Console.WriteLine("still running");
        Task.Delay(2000).Wait();
        Console.WriteLine("Not dead yet");
        Task.Delay(1000).Wait();
        Console.WriteLine("Task done");
        Task.Delay(5000);
    });

    bool success = real.Wait(time);
    if ( success )
    {
        Console.WriteLine("Task finished in time");
        await real;
    }
    else
    {
        Console.WriteLine("Task did not finish");
        real.Dispose();
        throw new TimeoutException("The task took too long");
    }
}

I already tried it with the cancellation token, but I do not have a loop to check the token every iteration. So I tried to do it with the Task.Wait(time) and I get the right message, but the task does not stop after using the Task.Dispose() method. I get the following output:

在此处输入图像描述

So I get the current output but the task continues to run in the back.. Any ideas on how to solve this?

Firstly: never Wait() on tasks (unless you know they have already finished); use await . As for the timeout: CancellationTokenSource can be made to time out after a delay, as below.

Note that cancellation-tokens do not interrupt code - you (or other code, as in the case of Task.Delay ) need to either check for cancellation (for example, ThrowIfCancellationRequested() ), or you need to use Register(...) to add a callback that will be invoked when it is cancelled.

using System;
using System.Threading;
using System.Threading.Tasks;

static class P
{

    public static async Task Main()
    {
        Console.WriteLine("starting app");
        try
        {

            Console.WriteLine("before");
            await DoStuffAsync(1000);
            Console.WriteLine("after");
        }
        catch
        {
            Console.WriteLine("TIMEOUT");
        }
        Console.WriteLine("Main finished wait 5 sec now");
        await Task.Delay(5000);
        Console.WriteLine("Closing app now");
    }
    public static async Task DoStuffAsync(int time)
    {
        using var cts = new CancellationTokenSource(time); // assuming here that "time" is milliseconds
        Task real = Task.Run(async () =>
        {
            await Task.Delay(2000, cts.Token);
            Console.WriteLine("Task Running");
            await Task.Delay(2000, cts.Token);
            Console.WriteLine("still running");
            await Task.Delay(2000, cts.Token);
            Console.WriteLine("Not dead yet");
            await Task.Delay(2000, cts.Token);
            Console.WriteLine("Task done");
            await Task.Delay(2000, cts.Token);
        });

        bool success;
        try
        {
            await real;
            success = true;
        }
        catch (OperationCanceledException)
        {
            success = false;
        }

        if (success)
        {
            Console.WriteLine("Task finished in time");
        }
        else
        {
            Console.WriteLine("Task tool too long");
        }
    }
}

Note that you can also pass a cancellation-token into Task.Run , but that simply gets checked before executing the callback - and there isn't usually a significant delay on that, so... it isn't usually worth it.

Additional note: if you want to be sure exactly what was cancelled (ie is the OperationCanceledException coming from cts ):

catch (OperationCanceledException cancel) when (cancel.CancellationToken == cts.Token)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM