0

I have a console app,

        {
            StartThread();
            //must be true, windows system wants to know it is started
            return true;
        } 

I'm trying to create a safety timeout function for this Task. But the task keeps running...

The method DoSomething calls other async methods and awaits their result

Do anyone have an idea why my task don't stop? Maybe a good code example on what to do

  public async void StartThread()
        {
             var tokenSource = new CancellationTokenSource();
                var token = tokenSource.Token;
                try
                {
                        var timeout = 1000;
                        Task task = new Task(() => DoSomething(token), token);
                        task.Start();

                        if (await Task.WhenAny(task, Task.Delay(timeout, token)) == task)
                        {
                            if (token.IsCancellationRequested)
                                task.Dispose();

                            await task;

                            if (task.IsCompleted)
                            {
                                task.Dispose();
                                tokenSource.Cancel();
                                tokenSource.Dispose();
                            }
                            else
                            {
                                log.WriteToFile("Timeout_ ");
                            }
                        }
                        else
                            tokenSource.Cancel();
                   }
                catch (Exception e)
                {
                    Console.WriteLine("--StartThread ...there is an exception----");
                }
                finally
                {
                    Thread.Sleep(300000); // 5 minutter
                    StartThread();
                }
            }

Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
Lise
  • 63
  • 12
  • Related answer: https://stackoverflow.com/questions/35645899/awaiting-task-with-timeout – richzilla Apr 26 '21 at 13:57
  • What does `DoSomething` do with the `CancellationToken`? – Stephen Cleary Apr 26 '21 at 14:05
  • DoSomething starts with cheking if it has been cancelled, after that i calls 2 other methods` public async Task DoSomething(CancellationToken ct) { var success = false; if (ct.IsCancellationRequested) ct.ThrowIfCancellationRequested(); List list = new List(); list = await GetShopList(); if (list.Count > 0) success = await GetReport(token_, list); return success; }` – Lise Apr 26 '21 at 14:20

3 Answers3

1

While not create CancellationTokenSource from given timeout?

var timeout = 1000;

//DONE: don't forget to dispose CancellationTokenSource instance 
using (var tokenSource = new CancellationTokenSource(timeout)) {
  try {
    var token = tokenSource.Token;

    //TODO: May be you'll want to add .ConfigureAwait(false);
    Task task = Task.Run(() => DoSomething(token), token);

    await task;

    // Completed
  }
  catch (TaskCanceledException) {
    // Cancelled due to timeout

    log.WriteToFile("Timeout_ ");
  } 
  catch (Exception e) {
    // Failed to complete due to e exception

    Console.WriteLine("--StartThread ...there is an exception----");

    //DONE: let's be nice and don't swallow the exception
    throw; 
  }
}
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • the tasks runnning in DoSomething method keeps running after the task is cancelled, how can i make them stop? – Lise Apr 27 '21 at 06:22
  • @Lise: Cancellation is *cooperative* in .Net; you should change / update `DoSomething` method; typical solution is to throw `TaskCanceledException` via `token.ThrowIfCancellationRequested();` call – Dmitry Bychenko Apr 27 '21 at 06:25
0

You should hardly ever Dispose a Task, since iot is managed by C# internals and it is taken care of. Also, you Dispose way too eagerly, for example:

if (token.IsCancellationRequested)
    task.Dispose();

await task;

I do not think so you want still await task if it cancelled and disposed. I guess it will not work at all.

Also if you use async, do not mix blocking calls such as Thread.Sleep - that can lead to disaster...

After all, you use cancellation token with some delay task to imitate a timeout - that's OK, but why do put unnecessary code, when you have great API at hand. Just make use of special contructor of CancellationTokenSource:

public CancellationTokenSource (int millisecondsDelay);

Here's the docs

Michał Turczyn
  • 32,028
  • 14
  • 47
  • 69
0

After a timeout you are setting the CancellationToken and then immediately sleeping the thread for 5 minutes. Thus DoSomething() never gets a chance to continue running and react to the token being cancelled.

GazTheDestroyer
  • 20,722
  • 9
  • 70
  • 103