How to wait synchronously on cancellation of async task - c#

I have a generic class which runs certain work packages asynchronously. It has the possibility to cancel the execution of all tasks and wait synchronously on the completion of the canceled tasks. The cancellation is triggered before a new transaction (the user does something) starts. This is necessary because the asynchronous task as well as the new transaction would change the same objects, but the asynchronous task would do it while assuming the state before the transaction.
Here a sample code why this behavior is so important:
private void Transaction()
{
asyncExecution.AbortAllAsyncWork();
DoTransaction();
}
This method is called synchronously and DoTransaction changes objects which are also changed in the asynchronous tasks. For example list could be changed while they are iterated.
Previously I achieved this behavior with the ContinueWith method on tasks where I passed a synchronous task scheduler. All in all it was hard to understand and seemed kind of dirty. Therefore I wondered if I could achieve the same behavior with the new async-await feature. The problem here lies in a deadlock described here. The code so far with the deadlock problem:
public void RunAsync<TWork, TResult>(IIncrementalAsyncExecutable<TWork, TResult> executable, TWork initialWork) where TWork : class
{
Task workingTask = RunAsyncInternal(executable, initialWork, CancellationTokenSource);
if (IsRunning(workingTask))
{
workingTasks.Add(workingTask);
}
}
private async Task RunAsyncInternal<TWork, TResult>(IIncrementalAsyncExecutable<TWork, TResult> executable, TWork initialWork, CancellationTokenSource tokenSource) where TWork : class
{
while (!executable.WorkDone)
{
TResult result = await Task.Run(() => executable.CalculateNextStep(initialWork));
executable.SyncResult(result);
if (tokenSource.IsCancellationRequested)
{
return;
}
}
}
public void AbortAllAsyncWork()
{
CancellationTokenSource.Cancel();
foreach (Task workingTask in workingTasks)
{
if (IsRunning(workingTask))
{
workingTask.Wait(); // here is the deadlock problem
}
}
}
Is there a possibility to achieve this behavior with the new async-await feature without deadlock?

I have a generic class which runs certain work packages asynchronously.
It's really much easier to use built-in types for this, like TPL Dataflow. They've done all the hard work.
The problem is, that the application is designed synchronously.
Yes, but note that the problem is in the application's design. Waiting for tasks to complete is an inherently asynchronous operation, and the best solution is definitely Yuval's.
Previously I achieved this behavior with the ContinueWith method on tasks where I passed a synchronous task scheduler.
I don't see how that could possibly avoid the deadlock you're seeing.
I want to find a solution, where there is no refactoring necessary.
What you're really asking is "how do I do sync-over-async". The best answer is "don't". But there are a few hacks that you can use to force it to work in some scenarios. There is no general-purpose solution that always works.
These hacks are: just block, push the operations onto a background thread, and run a nested message loop. They're described in more detail on Stephen Toub's blog.

If each Task is going to be cancelled, you can simply await on them and catch the OperationCanceledException:
public async Task AbortAllAsyncWork()
{
CancellationTokenSource.Cancel();
foreach (Task workingTask in workingTasks.Keys)
{
if (IsRunning(workingTask))
{
try
{
await workingTask;
}
catch (OperationCanceledException oce)
{
// Do something usefull
}
}
}
}
Or, you could simply await Task.WhenAll on all the tasks:
await Task.WhenAll(workingTasks.Keys)
Assuming Keys is an IEnumerable<Task>, the returned Task would be in a Canceled state.

Related

What is the difference between starting a worker via Task.Run and just calling an async method (don't await) with await Task.Yield inside? [duplicate]

I would like to ask you on your opinion about the correct architecture when to use Task.Run. I am experiencing laggy UI in our WPF .NET 4.5
application (with Caliburn Micro framework).
Basically I am doing (very simplified code snippets):
public class PageViewModel : IHandle<SomeMessage>
{
...
public async void Handle(SomeMessage message)
{
ShowLoadingAnimation();
// Makes UI very laggy, but still not dead
await this.contentLoader.LoadContentAsync();
HideLoadingAnimation();
}
}
public class ContentLoader
{
public async Task LoadContentAsync()
{
await DoCpuBoundWorkAsync();
await DoIoBoundWorkAsync();
await DoCpuBoundWorkAsync();
// I am not really sure what all I can consider as CPU bound as slowing down the UI
await DoSomeOtherWorkAsync();
}
}
From the articles/videos I read/saw, I know that await async is not necessarily running on a background thread and to start work in the background you need to wrap it with await Task.Run(async () => ... ). Using async await does not block the UI, but still it is running on the UI thread, so it is making it laggy.
Where is the best place to put Task.Run?
Should I just
Wrap the outer call because this is less threading work for .NET
, or should I wrap only CPU-bound methods internally running with Task.Run as this makes it reusable for other places? I am not sure here if starting work on background threads deep in core is a good idea.
Ad (1), the first solution would be like this:
public async void Handle(SomeMessage message)
{
ShowLoadingAnimation();
await Task.Run(async () => await this.contentLoader.LoadContentAsync());
HideLoadingAnimation();
}
// Other methods do not use Task.Run as everything regardless
// if I/O or CPU bound would now run in the background.
Ad (2), the second solution would be like this:
public async Task DoCpuBoundWorkAsync()
{
await Task.Run(() => {
// Do lot of work here
});
}
public async Task DoSomeOtherWorkAsync(
{
// I am not sure how to handle this methods -
// probably need to test one by one, if it is slowing down UI
}
Note the guidelines for performing work on a UI thread, collected on my blog:
Don't block the UI thread for more than 50ms at a time.
You can schedule ~100 continuations on the UI thread per second; 1000 is too much.
There are two techniques you should use:
1) Use ConfigureAwait(false) when you can.
E.g., await MyAsync().ConfigureAwait(false); instead of await MyAsync();.
ConfigureAwait(false) tells the await that you do not need to resume on the current context (in this case, "on the current context" means "on the UI thread"). However, for the rest of that async method (after the ConfigureAwait), you cannot do anything that assumes you're in the current context (e.g., update UI elements).
For more information, see my MSDN article Best Practices in Asynchronous Programming.
2) Use Task.Run to call CPU-bound methods.
You should use Task.Run, but not within any code you want to be reusable (i.e., library code). So you use Task.Run to call the method, not as part of the implementation of the method.
So purely CPU-bound work would look like this:
// Documentation: This method is CPU-bound.
void DoWork();
Which you would call using Task.Run:
await Task.Run(() => DoWork());
Methods that are a mixture of CPU-bound and I/O-bound should have an Async signature with documentation pointing out their CPU-bound nature:
// Documentation: This method is CPU-bound.
Task DoWorkAsync();
Which you would also call using Task.Run (since it is partially CPU-bound):
await Task.Run(() => DoWorkAsync());
One issue with your ContentLoader is that internally it operates sequentially. A better pattern is to parallelize the work and then sychronize at the end, so we get
public class PageViewModel : IHandle<SomeMessage>
{
...
public async void Handle(SomeMessage message)
{
ShowLoadingAnimation();
// makes UI very laggy, but still not dead
await this.contentLoader.LoadContentAsync();
HideLoadingAnimation();
}
}
public class ContentLoader
{
public async Task LoadContentAsync()
{
var tasks = new List<Task>();
tasks.Add(DoCpuBoundWorkAsync());
tasks.Add(DoIoBoundWorkAsync());
tasks.Add(DoCpuBoundWorkAsync());
tasks.Add(DoSomeOtherWorkAsync());
await Task.WhenAll(tasks).ConfigureAwait(false);
}
}
Obviously, this doesn't work if any of the tasks require data from other earlier tasks, but should give you better overall throughput for most scenarios.

C# Task.Delay(1).Wait() deadlocks but only if inside another Task [duplicate]

I don't quite understand the difference between Task.Wait and await.
I have something similar to the following functions in a ASP.NET WebAPI service:
public class TestController : ApiController
{
public static async Task<string> Foo()
{
await Task.Delay(1).ConfigureAwait(false);
return "";
}
public async static Task<string> Bar()
{
return await Foo();
}
public async static Task<string> Ros()
{
return await Bar();
}
// GET api/test
public IEnumerable<string> Get()
{
Task.WaitAll(Enumerable.Range(0, 10).Select(x => Ros()).ToArray());
return new string[] { "value1", "value2" }; // This will never execute
}
}
Where Get will deadlock.
What could cause this? Why doesn't this cause a problem when I use a blocking wait rather than await Task.Delay?
Wait and await - while similar conceptually - are actually completely different.
Wait will synchronously block until the task completes. So the current thread is literally blocked waiting for the task to complete. As a general rule, you should use "async all the way down"; that is, don't block on async code. On my blog, I go into the details of how blocking in asynchronous code causes deadlock.
await will asynchronously wait until the task completes. This means the current method is "paused" (its state is captured) and the method returns an incomplete task to its caller. Later, when the await expression completes, the remainder of the method is scheduled as a continuation.
You also mentioned a "cooperative block", by which I assume you mean a task that you're Waiting on may execute on the waiting thread. There are situations where this can happen, but it's an optimization. There are many situations where it can't happen, like if the task is for another scheduler, or if it's already started or if it's a non-code task (such as in your code example: Wait cannot execute the Delay task inline because there's no code for it).
You may find my async / await intro helpful.
Based on what I read from different sources:
An await expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off.
To wait for a single task to complete, you can call its Task.Wait method. A call to the Wait method blocks the calling thread until the single class instance has completed execution. The parameterless Wait() method is used to wait unconditionally until a task completes. The task simulates work by calling the Thread.Sleep method to sleep for two seconds.
This article is also a good read.
Some important facts were not given in other answers:
async/await is more complex at CIL level and thus costs memory and CPU time.
Any task can be canceled if the waiting time is unacceptable.
In the case of async/await we do not have a handler for such a task to cancel it or monitoring it.
Using Task is more flexible than async/await.
Any sync functionality can by wrapped by async.
public async Task<ActionResult> DoAsync(long id)
{
return await Task.Run(() => { return DoSync(id); } );
}
async/await generate many problems. We do not know if await statement will be reached without runtime and context debugging. If first await is not reached, everything is blocked. Sometimes even when await seems to be reached, still everything is blocked:
https://github.com/dotnet/runtime/issues/36063
I do not see why I must live with the code duplication for sync and async method or using hacks.
Conclusion: Creating Tasks manually and controlling them is much better. Handler to Task gives more control. We can monitor Tasks and manage them:
https://github.com/lsmolinski/MonitoredQueueBackgroundWorkItem
Sorry for my english.

Dealing with the boundary between async and synchronous code?

I am trying to write some asynchronous c# code, and I'm having a bit of trouble understanding the resources out there for async vs .Wait(). I have read many of the threads and websites, but somehow I'm still not sure how/why I should not use a wait. Goal of my program is this:
Kick off something asynchronously
Do some work
Wait for #1 to complete.
Do more work that requires #1 to be complete for
With tasks I have:
public static void Main()
{
Task t = DoWork();
DoMoreWork();
t.Wait();
DoWorkThatNeedsT();
}
public Task DoWork()
{
return Task.Run(() => {Thread.Sleep(1000);});
}
as far as I can tell, using async await in this instance just involves changing DoWork() to the following:
public async Task DoWork()
{
return await Task.Run(() => {Thread.Sleep(1000);});
}
Then I still have a .Wait() in the calling method. Is this supposed to get the benefits of thread-less asynchrony? Is there a different way I am supposed to be implementing this?
What you've described is not what async/await is used for. Async/await is used to release threads back to the operating system to be used by other systems while the system waits for something it does not have control over (for example, waiting for a sql statement to complete on a remote system).
What you want is to run task(s) in parallel with other code. Use Task.Run but don't worry about async/await, because you have nothing you're really waiting for.
Stephen Cleary - There is no thread is a great read to understand when to use async/await.

How does a Task get to know when it has completed?

The Task does not maintain a wait handle for performance reasons, and only lazily constructs one if the code were to ask one of it.
How then does a Task know it has been completed?
One would argue that the implementer sets the result on the TaskCompletionSource in their implementation but that would explain only the modern implementations and re-writes such as System.IO.FileStream.Begin/EndReadTask.
I followed the Task.IsComplete property; almost in every instance, an internal bitwise flag field (m_stateFlags) is set by the TrySetResult / TrySetException methods to indicate the status of the task.
But that does not cover all cases.
What about a method such as this?
public async Task FooAsync()
{
await Task.Run(() => { });
}
How then does a Task know it has been completed?
As I describe on my blog (overview, more detail), there are two kinds of tasks: Delegate Tasks (which execute code) and Promise Tasks (which represent an event).
Delegate Tasks complete themselves when their delegate completes.
Promise Tasks are completed from an external signal, using TaskCompletionSource<T> (or equivalent methods that are internal to the BCL).
I am answering my own question because I have suddenly remembered that I know the answer to it.
When using the C# Language Support Features
It's the state machine.
If the implementer of the asynchronous method used the C# language support such as the async keyword in the method declaration and the await keyword inside the method body to await an operation intrinsic to the task, then to the extent of the task he is implementing, the state machine signals task completion by setting the result of the task.
For e.g. if his implementation was as such:
// client code
public async void TopLevelMethod()
{
await MyMethodAsync();
}
// library code -- his implementation
public async Task MyMethodAsync()
{
await AnotherOperationAsync();
}
Then the completion of MyMethodAsync will be entrusted to the compiler generated state machine.
Of course, the signaling of completion of AnotherOperationAsync will also be taken care of by the compiler generated state machine, but that is not the point here.
Recall the states inside the MoveNext method indicate the task completion states and in the block inside of MoveNext that invokes the continuation callback, it also calls SetResult on the AsyncXXXMethodBuilder.
When not using the C# Language Support Features
If, however, the implementer of the asynchronous method did not make use of the C# language features, then it is the duty of the implementer to signal the completion of the task by setting the relevant result, exception or cancelled properties on the TaskCompletionSource object.
For e.g.
public Task MyMethodAsync()
{
var tcs = new TaskCompletionSource<object>();
try
{
AnotherOperation();
tcs.SetResult();
}
catch(Exception ex)
{
tcs.SetException(ex);
}
return tcs.Task;
}
If the implementer did not use TPL support or invoked another operation asynchronously using the older .NET API, then too, it is the implementer's responsibility to signal task completion by explicitly setting the status of the task through one of the Try/SetResult/Exception etc. methods.
For e.g.
public Task MyMethodAsync()
{
var tcs = new TaskCompletionSource...
var autoReseEvent = ...
ThreadPool.QueueUserWorkItem(new WaitCallback(() =>
{
/* Work */
Thread.SpinWait(1000);
tcs.SetResult(...);
autoResetEvent.Set();
};)...;
return tcs.Task;
}
An Ill-Advised Case
The best way to await a task is, of course, to use the await keyword. If, however, when implementing an asynchronous API, the implementer does this:
public Task MyMethodAsync()
{
return Task.Run(...);
}
That would leave the consumer of his API with a sour mouth, I suppose?
Task.Run should only ever be used in a fire and forget scenario where you do not care about the point in time when the task will be completed.
The one exception to this is if you awaited the task returned by the call to Task.Run using the await keyword, like the code snippet shown below, in which case, you would be using the language support as described in the first section.
public async Task MyMethodAsync()
{
await Task.Run(...);
}

Why does Task.WaitAll() not block or cause a deadlock here?

In the example below two await calls are used. To gain performance, the sample gets converted Task.WaitAll() instead (not really any faster, but this is just an example).
This is code from a library using Sqlite.Net on Android and the method gets called from OnResume() on the main UI thread:
public async Task SetupDatabaseAsync()
{
await CreateTableAsync<Session>();
await CreateTableAsync<Speaker>();
}
Here's the alternative:
public void SetupDatabaseAsync()
{
var t1 = CreateTableAsync<Session>();
var t2 = CreateTableAsync<Speaker>();
Task.WaitAll(t1, t2);
}
But from my understanding Task.WaitAll() should block the UI thread while waiting, thus leading to a deadlock. But it works just fine. Is that because the two calls don't actually invoke anything on the UI thread?
What's the difference if I use Task.WhenAll() instead? My guess it that it would work even if the UI thread would be invoked, just like with await.
I describe the details of the deadlock situation on my blog. I also have an MSDN article on SynchronizationContext that you may find helpful.
In summary, Task.WaitAll will deadlock in your scenario, but only if the tasks need to sync back to the UI thread in order to complete. You can conclude that CreateTableAsync<T>() does not sync back to the UI thread.
In contrast, this code will deadlock:
public async Task SetupDatabaseAsync()
{
await CreateTableAsync<Session>();
await CreateTableAsync<Speaker>();
}
Task.WaitAll(SetupDatabaseAsync());
I recommend that you not block on asynchronous code; in the async world, sync'ing back to the context is the default behavior (as I describe in my async intro), so it's easy to accidentally do it. Some changes to Sqlite.Net in the future may (accidentally) sync back to the original context, and then any code using Task.WaitAll like your original example will suddenly deadlock.
It's best to use async "all the way":
public Task SetupDatabaseAsync()
{
var t1 = CreateTableAsync<Session>();
var t2 = CreateTableAsync<Speaker>();
return Task.WhenAll(t1, t2);
}
"Async all the way" is one of the guidelines I recommend in my asynchronous best practices article.
When you're blocking the UI thread (and the current synchronization context) it will only cause a deadlock if one of the tasks that you're waiting on marshals a delegate to the current context and then waits on it (synchronously or asynchronously). Synchronously blocking on any async method isn't an instant deadlock in every single case.
Because async methods will, by default, marshal the remainder of the method to the current synchronization context and after every single await, and because the task will never finish until that happens, it means that synchronously waiting on methods that use async/await will often deadlock; at least unless the described behavior is explicitly overridden (through, say ConfigureAwait(false)).
Using WhenAll means that you're not blocking the current synchronization context. Instead of blocking the thread you're just scheduling another continuation to be run when all of the other tasks finish, leaving the context free to handle any other requests that are ready right now (like, say, the continuation from the underlying async method that WhenAll is waiting on).
Maybe this sample will demonstrate what might be happening. It's an iOS view loading. Try it with both the await call and without it (commented out below). Without any await in the function it will run synchronously and the UI will be blocked.
public async override void ViewDidLoad()
{
base.ViewDidLoad ();
var d1 = Task.Delay (10);
var d2 = Task.Delay (10000);
//await Task.Delay (10);
Task.WaitAll (d1, d2);
this.label.Text = "Tasks have ended - really!";
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear (animated);
this.label.Text = "Tasks have ended - or have they?";
}

Categories