My understanding is that Task.Run() is effectively fire and forget.
If you try to 'wait' for a Task.Run() to complete it will return almost immediately because it's 'task' is to launch the inner operation.
Once it's done that it's IsCompleted. It does not hook onto the inner operation.
So suppose you have 3 long-running sub-tasks, JobA(), JobB() and JobC(), to be completed sequentially...
public bool ExecuteLongRunningTasks(CancellationToken cancelToken = default)
{
if (!_JobACompleted)
{
JobA();
_JobACompleted = true;
if (cancelToken.IsCancellationRequested)
return false;
}
if (!_JobBCompleted)
{
JobB();
_JobBCompleted = true;
if (cancelToken.IsCancellationRequested)
return false;
}
JobC();
_AllJobsCompleted = true;
return true;
}
... and that at at some point the UI thread may require the results of these 3 sub-tasks (which have been launched asynchronously), then it stands to reason that you will allow a long running sub-task to complete asynchronously, and then have the better performing UI thread complete the uncompleted sub-tasks.
To achieve this I have to use StartNew() for the asynchronous operations because StartNew(), 'by default', hooks onto the operation it is launching...
public bool AsyncExecute()
{
// Property accessor that does a few sanity checks.
if (!ClearToLoadAsync)
return false;
_AsyncActive = true;
_AsyncTask = Task.Factory.StartNew<bool>(
() =>
{
ExecuteLongRunningTasks(_CancelToken);
_AsyncActive = false;
return true;
},
default, TaskCreationOptions.LongRunning, TaskScheduler.Default);
return true;
}
... and if the UI thread needs the results it uses the much maligned Wait()...
public bool SyncExecute()
{
// Just a property accessor that does some trivial deadlock and completion checks.
if (!ClearToLoadSync)
return false;
if (_AsyncActive)
{
// Post a cancel request and wait.
_CancelTokenSource.Cancel();
_AsyncTask.Wait();
}
if (!_AllJobsCompleted)
{
// Execute any outstanding long running tasks synchronously.
return ExecuteLongRunningTasks();
}
return true;
}
If anyone has a solution that achieves the same with Task.Run() I would love to see how it is done because I was unsuccessful.