Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

c# - 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:

enter image description here

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

question from:https://stackoverflow.com/questions/65915203/how-to-stop-async-task-after-a-certain-period-of-time

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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 (i.e. is the OperationCanceledException coming from cts):

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...