Mrinal Kamboj
Mrinal Kamboj

Reputation: 11482

Why the Task doesn't show canceled status

I am testing a simple console application created on Linqpad, idea is to have assured understanding of the working of Task and create a logic which works, when Task is completed, faulted or Canceled. I want to execute a logic only when Task is completed but not faulted or canceled.

void Main()
{
    CancellationTokenSource cts = new CancellationTokenSource(new TimeSpan(0,0,0,0,1000));

    Task t = Task.Run(() => Work(),cts.Token);
    try
    {
        t.Wait();
    }
    catch
    {
    }

    ("Completed :: " + t.IsCompleted).Dump();
    ("Canceled :: " + t.IsCanceled).Dump();
    ("Faulted :: " + t.IsFaulted).Dump();
}

public async Task Work()
{
    await Task.Delay(3000);
}

Following are the issues:

  1. I am able to confidently figure out the Completed and Faulted states, but even when in my view this code should lead to Task cancellation, the value of IsCanceled property is always false.

  2. Ideally when the Task is faulted, even though I am silently capturing the exception in a try catch block, it should show IsCompleted as false, but it always remain true, currently Linqpad doesn't have continue on error option, but I am assuming, it would turn false if I can continue on error

Upvotes: 2

Views: 587

Answers (3)

Stephen Cleary
Stephen Cleary

Reputation: 456417

Others have noted that your code is not observing the CancellationToken, and that's why the task is not being cancelled.

I'll answer this part of the question:

I want to execute a logic only when Task is completed but not faulted or canceled.

To do this, put your logic after you await the task:

await t;
// Your logic here.

Using IsCanceled / IsFaulted / IsCompleted for control flow is a code smell.

Upvotes: 5

Sefe
Sefe

Reputation: 14007

I am able to confidently figure out the Completed and Faulted states, but even when in my view this code should lead to Task cancellation, the value of IsCanceled property is always false.

There is no automatism in cancellation. You are passing CancellationToken to Task.Run. If cancellation would occur while the task is starting, the start process would be interrupted by cancellation. Once the task is running, it is the task's method's responsibility to check the cancellation token. Wait is not doing that. It does not even know of the cancellation token. Hence, the task can never turn into the canceled state.

This is how you would observe cancellation:

void Main()
{
    CancellationTokenSource cts = new CancellationTokenSource(new TimeSpan(0,0,0,0,1000));

    Task t = Task.Run(() => Work(cts.Token),cts.Token);
    try
    {
        t.Wait();
    }
    catch
    {
    }

    ("Completed :: " + t.IsCompleted).Dump();
    ("Canceled :: " + t.IsCanceled).Dump();
    ("Faulted :: " + t.IsFaulted).Dump();
}

public async Task Work(CancellationToken token)
{
    await Task.Delay(3000, token);
}

Ideally when the Task is faulted, even though I am silently capturing the exception in a try catch block, it should show IsCompleted as false, but it always remain true

Check MSDN:

IsCompleted will return true when the task is in one of the three final states: RanToCompletion, Faulted, or Canceled.

Upvotes: 5

Peter Bons
Peter Bons

Reputation: 29720

You did not pass the CancellationToken to the Task.Delay method, so nothing had to be cancelled. The token you pass in Task.Run(xxx) prevents the work from ever being started if the token has an outstanding cancellation. But your token is cancelled after 1 second, that is long after the call to Task.Run.

Try this:

void Main()
{
    CancellationTokenSource cts = new CancellationTokenSource(new TimeSpan(0, 0, 0, 0, 1000));

    Task t = Task.Run(() => Work(cts.Token), cts.Token);
    try
    {
        t.Wait();
    }
    catch
    {
    }

    ("Completed :: " + t.IsCompleted).Dump();
    ("Canceled :: " + t.IsCanceled).Dump();
    ("Faulted :: " + t.IsFaulted).Dump();
}

public async Task Work(CancellationToken t)
{
    await Task.Delay(3000, t);
}

Upvotes: 2

Related Questions