Firstly a forward apology: I cannot isolate the following bug into a simple console application. However, in my relatively simple ASP.NET Web Forms application, the following code will cause the current thread to block indefinitely:
public class MyModule : IHttpModule
{
public void Dispose()
{
}
public void Init(System.Web.HttpApplication context)
{
context.BeginRequest += this.Context_BeginRequest;
}
private void Context_BeginRequest(object sender, EventArgs e)
{
Sleep().Wait();
var x = 2; // This line is never hit.
}
private async Task Sleep()
{
await TaskEx.Run(() => System.Threading.Thread.Sleep(1000));
}
}
The task state just remains as 'WaitingForActivation'. Does anyone know why this would happen?
EDIT: The comment from Stephen Cleary sheds more light:
AspNetSynchronizationContext is the strangest implementation. It treats Post as synchronous rather than asynchronous and uses a lock to execute its delegates one at a time. AspNetSynchronizationContext does not require marshaling back to the same thread (but does need to take the lock); the deadlock on Wait is because the continuation is waiting for the lock (held by the thread in the event handler)
My guess is that there's a SynchronizationContext which is forcing the continuation to run on the same thread as the event handler. Your event handler is blocking that thread, so the continuation never runs, which means the event handler will never unblock.
That's only a guess though - it's the only thing I can think of which makes sense at the moment.
One option to try to unblock this is to change your Sleep method to:
private async Task Sleep()
{
await TaskEx.Run(() => System.Threading.Thread.Sleep(1000))
.ConfigureAwait(continueOnCapturedContext: false);
}
That will allow the continuation to complete on a different context.
I'm surprised there is such a synchronization context, mind you... I'd expect all of this to just happen on the thread pool. Possibly BeginRequest is treated slightly specially.
Related
I'm trying to check if boolean is true and if it's false keep checking until it's true. I find this and i don't really understand the example. I don't find anything and i try to do it easily but it isn't working it's freezing.
private void dashboard_Paint(object sender, PaintEventArgs e)
{
if (IsLogged().GetAwaiter().GetResult())
{
Console.WriteLine("Logged");
}
}
public async Task<Boolean> IsLogged()
{
while (!logged)
{
if (logged)
return true;
await Task.Delay(25);
}
return false;
}
Tasks in C# are a way to implement cooperative multitasking, where a number of tasks can potentially run on the same thread, each doing small amounts of work before yielding the cpu for other tasks to execute. If one of the tasks misbehaves and doesn't yield back to the task scheduler then the thread is blocked and no tasks will run until the block is cleared. When the task is invoked again it continues where it left off.
The default task scheduler runs tasks on a thread pool which helps to mitigate (but not eliminate) the impact of thread blocking. On WinForms though the task scheduler is set up to run tasks on the UI thread by default, since so many operations can only be done from the main thread. Overall this is a good thing, but it leads to problems whenever thread blocking comes up. Instead of blocking one of a group of thread pool threads, you're blocking the thread your UI and all of your other threads are running on.
The way to deal with this is to use async and await everywhere that it makes sense to do so. If you're ever waiting on a task to finish, use await to do it. If you ever find yourself using .Result, .Wait() or .GetAwaiter().GetResult() then ask yourself whether it can be rewritten as an async method, even if you have to use async void for event handlers.
For your paint event that means doing this:
private async void dashboard_Paint(object sender, PaintEventArgs e)
{
if (await IsLogged())
Console.WriteLine("Logged");
}
(While you shouldn't use async void in general, this is a requirement for async event handlers since the event signature is delegate void X(...) not delegate Task X(...).)
I won't get into why you should never have a wait in an OnPaint event handler, or why your IsLogged example has issues (and should probably be called WaitLogged instead), but there's one thing that you might want to be aware of just in case: the volatile keyword.
Assuming that logged is a field rather than a property, the optimizer can capture the value of the field and continue to use that captured value for the life of the method. The volatile keyword tells the optimizer that this shouldn't happen, and that every reference to logged should always result in a read from the variable rather than the captured value.
In the worst case you can end up with optimized code that looks something like this:
private async Task<bool> IsLogged()
{
if (!logged)
{
while (true)
await Task.Delay(25)
}
return true;
}
From the optimizer's point of view, that's what your code does. It doesn't know that the logged value can be changed by something else, so it doesn't consider that options. Adding volatile lets it know that it can't do that.
private async Task dashboard_Paint(object sender, PaintEventArgs e)
{
if (await IsLogged())
{
Console.WriteLine("Logged");
}
}
That should solve the issue with the freezing because GetAwaiter() sometimes freezes if not used correctly.
Have you tried checking to see what is setting the logging boolean to true? It seems like an infinite loop.
The behavior of Task.Wait() is unexpectedly different depending on the "environment" where invoked.
Calling Task.Wait() during application startup with below async method TestAsync passes (doesn't cause a deadlock) while the same code blocks when called from within a WPF Button handler.
Steps to reproduce:
In Visual Studio, using the wizard, create a vanilla WPF .NET framework application (e.g. named WpfApp).
In the App.xaml.cs file of the app file paste below Main method and TestAsync method.
In the project properties set Startup object to WpfApp.App.
In the properties of App.xaml switch Build Action from ApplicationDefinition to Page.
public partial class App : Application
{
[STAThread]
public static int Main(string[] args)
{
Task<DateTime> task = App.TestAsync();
task.Wait();
App app = new App();
app.InitializeComponent();
return app.Run();
}
internal static async Task<DateTime> TestAsync()
{
DateTime completed = await Task.Run<DateTime>(() => {
System.Threading.Thread.Sleep(3000);
return DateTime.Now;
});
System.Diagnostics.Debug.WriteLine(completed);
return completed;
}
}
Observe that the application starts properly (after 3sec delay) and that the "completed" DateTime is written to debug output.
Next create a Button in MainWindow.xaml with Click handler Button_Click in MainWindow.xaml.cs
public partial class MainWindow : Window
{
...
private void Button_Click(object sender, RoutedEventArgs e)
{
Task<DateTime> task = App.TestAsync();
task.Wait();
}
}
Observe that after clicking the Button, the application is deadlocked.
Why can't it pass in both cases?
Is there a way to change invocation (e.g. using ConfigureAwait at the correct task or somehow setting SynchronizationContext or whatever) so that it behaves identical in both invocations, but still synchronously waits for completion?
Update on limitations of the solution.
The async method like TestAsync comes from a library that cannot be changed.
The invocation code of the TestAsync method is nested within a callstack that cannot be changed either, and the code outside the callstck makes use of the returned value of the async method.
Ultimately the solution code has to convert the async method to run synchronous by not changing the method nor the caller.
This works well within UT code (NUnit) and during application startup, but no more within a handler of WPF.
Why?
There are a couple of different ways that you can handle this situation, but ultimately the reason there is a deadlock in one situation and not the other is that when called in the Main method SynchronizationContext.Current is null, so there isn't a main UI context to capture and all async callbacks are handled on thread pool threads. When called from the button, there is a synchronization context which is captured automatically, so all async callbacks in that situation are handled on the main UI thread which is causing the deadlock. In general the only way you won't get that deadlock is by forcing the async code to not capture the synchronization context, or use async all the way up and don't synchronously wait from the main UI context.
you can ConfigureAwait(false) inside of your TestAsync method so that it doesn't capture the synchronization context and try to continue on the main UI thread (this is ultimately what is causing your deadlock because you are calling task.Wait() on the UI thread which is blocking the UI thread, and you have System.Diagnostics.Debug.WriteLine(completed); that is trying to be scheduled back onto the UI thread because await automatically captures the synchronization context)
DateTime completed = await Task.Run<DateTime>(() => {
System.Threading.Thread.Sleep(3000);
return DateTime.Now;
}).ConfigureAwait(false);
You can start the async task on a background thread so that there isn't a synchronization context to capture.
private void Button_Click(object sender, RoutedEventArgs e)
{
var task = Task.Run(() => App.TestAsync());
var dateTime = task.Result;
}
you can use async up the whole stack
private async void Button_Click(object sender, RoutedEventArgs e)
{
Task<DateTime> task = App.TestAsync();
var dateTime = await task;
}
Given how you are using it, if you don't have to wait until the task is done, you can just let it go and it will finish eventually, but you lose the context to handle any exceptions
private void Button_Click(object sender, RoutedEventArgs e)
{
//assigning to a variable indicates to the compiler that you
//know the application will continue on without checking if
//the task is finished. If you aren't using the variable, you
//can use the throw away special character _
_ = App.TestAsync();
}
These options are not in any particular order, and actually, best practice would probably be #3. async void is allowed specifically for cases like this where you want to handle a callback event asynchronously.
From what I understand, in .NET many of the front ends have a single UI thread, and therefore must be written async all the way through. Other threads are reserved and utilized for things like rendering.
For WPF, this is why use of the Dispatcher and how you queue up work items is important, as this is your way to interact with the one thread you have at your disposal. More reading on it here
Ditch the .Result as this will block, rewrite the method as async, and call it from within the Dispatch.Invoke() and it should run as intended
Why can't it pass in both cases?
The difference is the presence of a SynchronizationContext. All threads start out without a SynchronizationContext. UI applications have a special UI thread(s) and at some point they need to create a SynchronizationContext and install it on that thread(s). Exactly when this happens isn't documented (or consistent), but it has to be installed at the point the UI main loop starts.
In this case, WPF will install it (at the latest) within the call to Application.Run. All user invocations from the UI framework (e.g., event handlers) happen within this context.
The blocking code deadlocks with the context because this is the classic deadlock situation, which requires three components:
A context that only allows one thread at a time.
An asynchronous method that captures that context.
A method also running in that context that blocks waiting for that asynchronous method.
Before the WPF code installed the context, condition (1) wasn't met, and that's why it didn't deadlock.
Is there a way to change invocation (e.g. using ConfigureAwait at the correct task or somehow setting SynchronizationContext or whatever) so that it behaves identical in both invocations, but still synchronously waits for completion?
We-ell...
This is a rephrasing of "how do I block on asynchronous code", and there's no good answer for that. The best answer is to not block on asynchronous code at all; i.e., use async all the way. Especially since this is GUI code, I'd say for the sake of UX you really want to avoid blocking. Since you're on WPF, you may find a technique like asynchronous MVVM data binding useful.
That said, there are a few hacks you can use if you must. Using ConfigureAwait is one possible solution, but not one I recommend; you'd have to apply it to all awaits within the transitive closure of all methods being blocked on (Blocking Hack). Or you can shunt the work to the thread pool (Task.Run) and block on that (Thread Pool Hack). Or you can remove the SynchronizationContext - unless the code being blocked on manipulates UI elements or bound data. Or there are even more dangerous hacks that I really can't recommend at all (Nested Message Loop Hack).
But even after putting in all the work for a hack, you'll still end up blocking the UI. The hacks are hard precisely because they're not recommended. It's quite a bit of work to give your users a worse experience. The far, far better solution (for your users and future code maintainers) is to go async all the way.
First, sorry for yet another "why my async action hangs" question but I believe this question is different enough.
Surveying dozens of similar questions, the problem of async action deadlock is either in locking yourself out (.Result), using limited resources or using library components incorrectly (web requests seems popular). In the following example, I cannot find any from above:
private async Task ExecuteAsync(Task<int> task)
{
// entering on current thread, that is the main UI thread
await task // execute "task" asynchronnously (on a different thread)
.ConfigureAwait(false); // when done, no need to return to main thread
MessageBox.Show("success"); // succes indicator
}
public MainWindow() //wpf window ctor
{
InitializeComponent();
this.Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
var task = new Task<int>(() => 42); // make an Action wrapping sychronnous method
// fire and forget, never caring for .Result, disard even the task
var _ = ExecuteAsync(task).ConfigureAwait(false);
}
I have commented the sample with my best try on exaplaining how things (should) work, but something in my explanation must be wrong. Even though MainWindow ctor does not deadlock, the Action () => 42 is never executed and "success" message is not shown. After some debugging I managed to fix the sample (using Task.FromResult), but I am still not sure what is wrong with it as it is now and even more importantly why.
What is the error in my reasoning and why was the action never executed/finished?
You did not start the task! You only declared it. Simply awaiting it does not "fire" it.
private async Task ExecuteAsync(Task<int> task)
{
// at first do start the task
task.Start();
await task.ConfigureAwait(false);
MessageBox.Show("success");
}
Note that ConfigureAwait(false) does not guarantee that execution will be continued on a different thread. It only says that you don't need it to be resumed on the original thread. And resuming UI work (like MessageBox.Show()) on a non-UI thread is not recommended.
As NineBerry pointed out, if you want to wrap a synchronous method and let it run on a different thread, you should use Task.Run():
var task = Task.Run(() => YourSynchronousCall());
Before I use
protected async void OnResume() {
await DoWorkAsync(); // assume exception is appropriately handled
await DoOtherWorkAsync();
}
But now I saw other developers use
protected void OnResume() {
SynchronizationContext.Current.Post(async (status) => {
await DoWorkAsync();
await DoOtherWorkAsync();}, null);
}
Is the second one correct and preferred when calling async methods inside non-async methods? Thank you in advance.
UPDATE:
If you use the 2nd snippet, you must call SynchronizationContext.Current.Post() on UI Thread, or you will get NullReferenceException, cause SynchronizationContext.Current is null on non-UI Thread. _handler.Post(async() => {// do UI changes}); can be called on non-UI Thread to do any UI changes, as long as _handler is instantiated on UI Thread.
No, don't use SynchronizationContext. You're already on the UI thread, so the second option really makes no sense.
Note that normally async void should be avoided. In this case, I'd say it's acceptable because you're actually treating OnResume as though it were an event handler:
protected async void OnResume()
{
await DoWorkAsync();
}
Both examples are performing unnecessary work. The best implementation of the method would be:
protected void OnResume()
{
DoWorkAsync();
}
In the first case you're forcing a continuation to run in the current context but that continuation has nothing to actually do; it's just pointlessly adding a post to the synchronization context.
The second snippet is adding two pointless posts two the current synchronization context, one explicitly, and one implicitly.
Both methods also have async methods that are adding state machines, even though you don't actually leverage any of that functionality, so that overhead is all entirely wasted.
I am running a process on a separate thread to facilitate concurrency and a smooth user interface calling
private void ThreadedTestConnection(SqlConnection conn, bool bShowErrMsg)
{
Task<bool> asyncTestConn = Task.Factory.StartNew<bool>
(() => TestConnection(conn, bShowErrMsg));
return asyncTestConn.Result;
asyncTestConn.Dispose();
}
from the UI thread. However, the 'wait' caused by return asyncTestConn is stopping the UI thread being release back to the GUI. I have come up with the following fix. From an event fired from the GUI I have (not including try/catch blocks)
private void SomeClick_Event(object sender, EventArgs e)
{
Task testConnection = Task.Factory.StartNew
(() => UtilsDB.ThreadedTestConnection(mainConn, true));
}
This works. That is, it returns control to the GUI immediately whilst running the test on a seperate background thread. Am I being a very foolish boy in doing this, or is this Okay?
Note: This is a seperate question but related to this one I have not recived a satasfactory answer for.
This is perfectly fine, you are just starting a "fire and forget" task which will run on a thread-pool thread - however in the first example you seem to expect a result (I assume a boolean indicating whether the connection test was successful) - in the second you won't have any - unless your task e.g. raises an event or calls a predefined callback.