I have code with looks something like:
I was trying to avoid putting it in a Task.Run because it is async and should run fine on the main thread
However it does not do a context switch (and will run forever), unless I insert a Task.Delay into the loop
Is there a better way of achieving this (Without Task.Run)?
var tasks = new List<Task>();
var cts = new CancellationTokenSource();
tasks.Add(DoSomething(cts.Token));
cts.Cancel();
Task.WaitAll(tasks.ToArray());
Console.WriteLine("Done");
async Task DoSomething(CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
await Task.CompletedTask;
await Task.Delay(1); // Without this is doesn't do context switch
}
}
I'm trying to unit test cancellation when I have a heavy workload an encountered this problem.
CodePudding user response:
Try
async Task DoSomething(CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
//await Task.CompletedTask; //you can omit this line
await Task.Yield();
}
}
CodePudding user response:
If you want to simulate a cancelable operation, the simplest way is probably this:
Task DoSomething(CancellationToken cancellationToken)
{
return Task.Delay(Timeout.Infinite, cancellationToken);
}
The cancellationToken
parameter has canceling semantics, meaning that when the token is canceled, the Task
will transition to the Canceled
state. If you want it to have stopping semantics, which is the non standard semantics for a CancellationToken
, you could do this:
async Task DoSomething(CancellationToken stoppingToken)
{
try { await Task.Delay(Timeout.Infinite, stoppingToken); }
catch (OperationCanceledException) { }
}
Now when the token is canceled, the Task
will transition to the RanToCompletion
state. Be aware that it's extremely rare to see a CancellationToken
parameter with stopping semantics in the standard .NET libraries.