Reputation: 11482
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:
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.
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
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
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
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