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.