I just realized that when i start a task from within a task and call Task.Wait the new task will not be inlined, while calling Task.Result will always inline the task.
As we wrap our tasks with a RAII pattern (implemented in ExecuteWithCancel), inlining will reuse allocated resources and is preferable.
But we sometime want to wait a certain time and cancel the task after that.
The waiting code looks like this:
using (var cts = new CancellationTokenSource())
{
// Task scheduler decides whether to execute synchronous or asynchronous
var task = new Task<TResult>(() => ExecuteWithCancel<TResult>(cts.Token, nameOfTaskPerformer, arguments), cts.Token)
if (timeout==TimeSpan.Zero || task.Wait(timeout)) // this creates an all or nothing timeout
return task.Result;
cts.Cancel();
throw new TimeoutException("");
}
When timeout is TimeSpan.Zero the Task is inlined, otherwise it always uses another thread.
Is there an easy way to redesign this code to use inlining and waiting/timeout?
Pretty sure that’s not possible. Suppose you are running the following code on thread A:
If the task is inlined, thread A will block indefinitely – how will it wake up after the timeout?
Looking at the reference source (Task.cs) we can see exactly that:
As per your question, in order to benefit from inlining with finite timeouts, you’d have to implement the timeout logic inside the task itself, perhaps something like:
And then use a regular
Wait()(orResult).