I'm trying to create a class that has synchronous methods and calls some other library methods which are asynchronous. For that reason I use Task.Result to wait for the async operation to finish. My methods are called by WPF app in synchronous way. This leads to a deadlock. I know that the best way is to make all my methods asynchronous but my situation requires them to be synchronous. From the other hand they use other library which is asynchronous.
My question is: How can I avoid the deadlock in such situation?
Steps to reproduce:
User hits a button in the app (method Button1_OnClick)
This method creates an instance of IPlugin and then calls its method RequestSomething()
This method then calls async library this way: asyncTarget.MethodFromAsyncLibrary("HelloFromPlugin").Result
The library calls back its method NotifyNewValueProgressAsync()
NotifyNewValueProgressAsync() delegates the call back to the WPF application
Since the UI context is blocked by this line asyncTarget.MethodFromAsyncLibrary("HelloFromPlugin").Result the callback in step 5 leads to a deadlock.
See code example below and related comments:
public class SyncAdapterPlugin : IPlugin, IProgressAsyncHandler
{
//Constructor and fields are omitted here
//This method is called from UI context by WPF application and it delegates synchronous call to asynchronous method
string IPlugin.RequestSomething()
{
//In order to be able to run the callback I need to capture current UI context
_context = TaskScheduler.FromCurrentSynchronizationContext();
var asyncTarget = new ClassFromMyLibrary1(this);
var resultFromAsyncLibrary = asyncTarget.MethodFromAsyncLibrary("HelloFromPlugin").Result; //Deadlock here!
return resultFromAsyncLibrary;
}
//This method does opposite, it delegates asynchronous callback to synchronous
async Task<bool> IProgressAsyncHandler.NotifyNewValueProgressAsync(string message)
{
//NotifyNewValueProgress method is implemented by WPF application and will update UI elements.
//That's why it's needed to run the callback on captured UI context.
Func<bool> work = () => _syncProgressHandler.NotifyNewValueProgress(message);
if (_context != null)
{
return await
Task.Factory.StartNew(work, CancellationToken.None, TaskCreationOptions.None, _context)
.ConfigureAwait(false);
}
return work();
}
}
Complete code example is here https://dotnetfiddle.net/i48sRc.
FYI, Some background on this issue you can also find in this SO question.
The plugin framework is fundamentally flawed. In particular, it requires a synchronous RequestSomething that expects to be able to call NotifyNewValueProgressAsync to update the UI. However, it's not possible to display a UI update while the UI thread is running a synchronous method.
This forces you to use one of the most dangerous and evil sync-over-async hacks: the nested message loop hack (as briefly described in my article on brownfield async). Since this is a WPF app, you'd use a nested dispatcher frame. The main pain with this hack is that it introduces reentrancy across your entire UI layer, which is the most subtle and difficult kind of concurrency problem.
By definition a synchronous method isn't going to be asynchronous. You will need to wrap the calls to the synchronous methods from the UI in a Task using TAP and await them there while making the method you await from asynchronous.
Related
I'm trying to learn more about the SynchronizationContext, so I made this simple console application:
private static void Main()
{
var sc = new SynchronizationContext();
SynchronizationContext.SetSynchronizationContext(sc);
DoSomething().Wait();
}
private static async Task DoSomething()
{
Console.WriteLine(SynchronizationContext.Current != null); // true
await Task.Delay(3000);
Console.WriteLine(SynchronizationContext.Current != null); // false! why ?
}
If I understand correctly, the await operator captures the current SynchronizationContext then posts the rest of the async method to it.
However, in my application the SynchronizationContext.Current is null after the await. Why is that ?
EDIT:
Even when I use my own SynchronizationContext it is not captured, although its Post function is called. Here is my SC:
public class MySC : SynchronizationContext
{
public override void Post(SendOrPostCallback d, object state)
{
base.Post(d, state);
Console.WriteLine("Posted");
}
}
And this is how I use it:
var sc = new MySC();
SynchronizationContext.SetSynchronizationContext(sc);
Thanks!
The word "capture" is too opaque, it sounds too much like that is something that the framework is supposed to. Misleading, since it normally does in a program that uses one of the default SynchronizationContext implementations. Like the one you get in a Winforms app. But when you write your own then the framework no longer helps and it becomes your job to do it.
The async/await plumbing gives the context an opportunity to run the continuation (the code after the await) on a specific thread. That sounds like a trivial thing to do, since you've done it so often before, but it is in fact quite difficult. It is not possible to arbitrarily interrupt the code that this thread is executing, that would cause horrible re-entrancy bugs. The thread has to help, it needs to solve the standard producer-consumer problem. Takes a thread-safe queue and a loop that empties that queue, handling invoke requests. The job of the overridden Post and Send methods is to add requests to the queue, the job of the thread is to use a loop to empty it and execute the requests.
The main thread of a Winforms, WPF or UWP app has such a loop, it is executed by Application.Run(). With a corresponding SynchronizationContext that knows how to feed it with invoke requests, respectively WindowsFormsSynchronizationContext, DispatcherSynchronizationContext and WinRTSynchronizationContext. ASP.NET can do it too, uses AspNetSynchronizationContext. All provided by the framework and automagically installed by the class library plumbing. They capture the sync context in their constructor and use Begin/Invoke in their Post and Send methods.
When you write your own SynchronizationContext then you must now take care of these details. In your snippet you did not override Post and Send but inherited the base methods. They know nothing and can only execute the request on an arbitrary threadpool thread. So SynchronizationContext.Current is now null on that thread, a threadpool thread does not know where the request came from.
Creating your own isn't that difficult, ConcurrentQueue and delegates help a lot of cut down on the code. Lots of programmers have done so, this library is often quoted. But there is a severe price to pay, that dispatcher loop fundamentally alters the way a console mode app behaves. It blocks the thread until the loop ends. Just like Application.Run() does.
You need a very different programming style, the kind that you'd be familiar with from a GUI app. Code cannot take too long since it gums up the dispatcher loop, preventing invoke requests from getting dispatched. In a GUI app pretty noticeable by the UI becoming unresponsive, in your sample code you'll notice that your method is slow to complete since the continuation can't run for a while. You need a worker thread to spin-off slow code, there is no free lunch.
Worthwhile to note why this stuff exists. GUI apps have a severe problem, their class libraries are never thread-safe and can't be made safe by using lock either. The only way to use them correctly is to make all the calls from the same thread. InvalidOperationException when you don't. Their dispatcher loop help you do this, powering Begin/Invoke and async/await. A console does not have this problem, any thread can write something to the console and lock can help to prevent their output from getting intermingled. So a console app shouldn't need a custom SynchronizationContext. YMMV.
By default, all threads in console applications and Windows Services only have the default SynchronizationContext.
Kindly refer to the MSDN article Parallel Computing - It's All About the SynchronizationContext. This has detailed information regarding SynchronizationContexts in various types of applications.
To elaborate on what was already pointed out.
The SynchronizationContext class that you use in the first code snippet is the default implementation, which doesn't do anything.
In the second code snippet, you create your own MySC context. But you are missing the bit that would actually make it work:
public override void Post(SendOrPostCallback d, object state)
{
base.Post(state2 => {
// here we make the continuation run on the original context
SetSynchronizationContext(this);
d(state2);
}, state);
Console.WriteLine("Posted");
}
Implementing your own SynchronizationContext is doable, but not trivial. It's much easier to use an existing implementation, like the AsyncContext class from the Nito.AsyncEx.Context package. You can use it like this:
using System;
using System.Threading;
using System.Threading.Tasks;
using Nito.AsyncEx;
public static class Program
{
static void Main()
{
AsyncContext.Run(async () =>
{
await DoSomethingAsync();
});
}
static async Task DoSomethingAsync()
{
Console.WriteLine(SynchronizationContext.Current != null); // True
await Task.Delay(3000);
Console.WriteLine(SynchronizationContext.Current != null); // True
}
}
Try it on Fiddle.
The AsyncContext.Run is a blocking method. It will complete when the supplied asynchronous delegate Func<Task> action completes. All asynchronous continuations are going to run on the console application's main thread, provided that there is no Task.Run or ConfigureAwait(false) that would force your code to exit the context.
The consequences of using a single-threaded SynchronizationContext in a console application are that:
You'll no longer have to worry about thread-safety, since all your code will be funneled to a single thread.
Your code becomes susceptible to deadlocks. Any .Wait(), .Result, .GetAwaiter().GetResult() etc inside your code is very likely to cause your application to freeze, in which case you'll have to kill the process manually from the Windows Task Manager.
I have a constructor that is called on UI thread in my WPF app. Inside of it, it calls async method but it must be done in a synchronous way. So I tried to call wait, but it caused deadlock an I understand why. So I introduced argument that indicates if method should be run in a asynchronous or synchronous manner. Something like this:
// constructor that is called on UI thread
public MyClass()
{
Method1(false).Wait();
}
public async Task Method1(bool runAsync)
{
await Method2(runAsync);
}
public async Task Method2(bool runAsync)
{
if (runAsync)
{
await Task.Run(() => Thread.Sleep(1000));
}
else
{
Thread.Sleep(1000);
}
}
I don't want to use ConfigureAwait because I want everything to run on UI thread. Will Method1(false).Wait(); ever cause a deadlock (is it safe to use)? I tested it a lot and it didn't, but I'm not sure. Finally, my real question is: if 'await Task.Run(...' is never executed, is my method completely synchronous? I found several posts on this subject, but none of them answers directly to my question.
I have a constructor that is called on UI thread in my WPF app. Inside of it, it calls async method but it must be done in a synchronous way.
I'm gonna stop you right there. The best solution is not to run synchronous/blocking code on the UI thread. That degrades your user experience. Instead, you should restructure your code so that you're never in this situation in the first place.
When a UI is being shown, the UI framework asks your code for the data to display. Your code should run synchronously and return immediately (not blocking). But your code also needs to do some asynchronous work in order to have the data to display. So there's a conflict there.
The solution is to design an intermediate state for your UI, e.g., a "loading..." message or a spinner. Then, when your code starts, it can synchronously/immediately display the "loading" state (and start the asynchronous operation), and when the asynchronous data arrives, the code updates the UI to the "final" state.
I discuss this pattern in more detail in my article on async MVVM data.
Instead of wrestling with async stuff at construction (your blocking solution isn't so good), why not write an async factory to spew out these objects?
class MyClass
{
public MyClass()
{
}
public async Task Method2(bool runAsync)
{
//async immediately
await Task.Delay(1000); //no Thread.Sleep. Blocking code != good
}
}
then
public MyClassFactory
{
public async Task<MyClass> GetAsync()
{
var c = new MyClass();
await c.Method2();
return c;
}
}
I’m using MvvmCross and the AsyncEx library within a Windows 10 (UWP) App.
In a ViewModel, I have an INotifyTaskCompletion property (1) which is wired-up to an Async method in the ViewModel (2)
In (2), I call an Async library method which:
Checks a local cache
Downloads data asynchronously
Adds the data to the cache
The caching code cannot be made asynchronous and so the library method contains both blocking and asynchronous code.
Q. What’s the best way to prevent blocking the UI thread?
I understand from Stephen Cleary to not to block in asynchronous code and not use Task.Run in library methods. So do I have to….
Move the caching calls into (2) e.g.
Use Task.Run (to check the cache)
Call the library method asynchronously
Use Task.Run again (to cache the data)?
Is there a better way?
If you have completely synchronous code which you can't change to make it return an awaitable, and want to make it asynchronous, then yes, your only choice if you want to use async/await is to use Task.Run().
Something like:
public async Task<T> MyMethod()
{
T result = await Task.Run(() => CheckCacheOnSyncMethodICantChange());
if(result != null)
{
result = await MyLibraryMethodThatReturnsATask();
await Task.Run(() => AddToCacheOnSyncMethodICantChange(result));
}
return result;
}
Should be ok.
I have the following async long running method inside my asp.net mvc-5 web application :-
public async Task<ScanResult> ScanAsync(string FQDN)
{
// sample of the operation i am doing
var c = await context.SingleOrDefaultAsync(a=>a.id == 1);
var list = await context.Employees.ToListAsync();
await context.SaveChangesAsync();
//etc..
}
and i am using Hangfire tool which support running background jobs to call this async method on timely basis, but un-fortuntly the hangefire tool does not support calling async methods directly . so to overcome this problem i created a sync version of the above method , as follow:-
public void Scan()
{
ScanAsync("test").Wait();
}
then from the HangFire scheduler i am calling the sync method as follow:-
RecurringJob.AddOrUpdate(() => ss.Scan(), Cron.Minutely);
so i know that using .Wait() will mainly occupy the iis thread during the method execution ,, but as i mentioned i need to do it in this way as i can not directly call an async TASK inside the hangefire scheduler .
so what will happen when i use .Wait() to call the async method ?, will the whole method's operations be done in a sync way ? for example as shown above i have three async operations inside the ScanAsync() ;SingleOrDefualtAsync,ToListAsync & SaveChangesAsync, so will they be executed in sync way because i am calling the ScanAsync method using .wait() ?
so what will happen when i use .Wait() to call the async method ?,
will the whole method's operations be done in a sync way ? for example
as shown above i have three async operations inside the ScanAsync()
;SingleOrDefualtAsync,ToListAsync & SaveChangesAsync, so will they be
executed in sync way because i am calling the ScanAsync method using
.wait() ?
The methods querying the database will still be executed asynchronously, but the fact that you're calling Wait means that even though you're releasing the thread, it wont return to the ASP.NET ThreadPool as you're halting it.
This is also a potential for deadlocks, as ASP.NET has a custom synchronization context which makes sure the context of the request is availiable when in a continuation of an async call.
I would recommend that instead, you'd use the synchronous API provided by entity-framework, as you won't actually be enjoying the scalability one can get from asynchronous calls.
Edit:
In the comments, you asked:
As i am currently doing with hangefire eliminate the async effect ? if yes then will it be better to use sync methods instead ? or using sync or async with hangeffire will be exactly the same
First, you have to understand what the benefits of async are. You don't do it because it's cool, you do it because it serves a purpose. What is that purpose? Being able to scale under load. How does it do that? When you await an async method, control is yielded back to the caller. For example, you have an incoming request, you query you database. You can either sit there and wait for the query to finish, or you can re-use that thread to serve more incomong requests. That's the true power.
If you don't actually plan on receiving a decent amount of requests (such that you'll starve the thread-pool), you won't actually see any benefit from async. Currently, the way you've implemented it, you won't see any of those benefits because you're blocking the async calls. All you'll see, possibly, are deadlocks.
This very much depends on the way HangFire is implemented. If it just queuing tasks to be invoked in ThreadPool the only effect will be, that one of your threads will be blocked until the request is ended. However if there is a custom SynchronizationContext this can lead to a serious deadlock.
Consider, if you really want to wait for your scheduled job to be done. Maybe all you want is just a fire and forget pattern. This way your method will be like:
public void Scan()
{
ScanAsync("test"); // smoothly ignore the task
}
If you do need to wait, you can instead try using async void method:
public async void Scan()
{
await ScanAsync("test");
DoSomeOtherJob();
}
There are many controversies about using async void as you cannot wait for this method to end, nor you can handle possible errors.
However, in event driven application this can be the only way. For more informations you can refer to: Async Void, ASP.Net, and Count of Outstanding Operations
I'm not sure if this is a SignalR issue or an async/await issue. When my client app (WPF) starts up, it does some initialisation:-
public async void Initialise()
{
// Get data from the server - async, as it may be long-running.
var data = await _hubProxy.Invoke<FooData>("Method1");
_dataProcessor.ProcessData(data);
}
The _dataProcessor is a helper class that does some stuff with the data passed to it, then at some point calls a different server method using a line similar to:-
var moreData = _hubProxy.Invoke<BarData>("Method2").Result;
None of the code in the helper class is async.
The first server invoke (in Initialise()) works fine - it gets back the data and passes it to the helper class. This proceeds without issue until its invoke - it gets called but never returns, and the thread never proceeds past this line. I've put a breakpoint in the server method and can confirm that it is being called and returning a value, but for some reason this is not getting back to the client.
The strange thing is, if I take out the async/await keywords in the Initialise() method, everything works fine. What am I doing wrong? Why would these keywords affect the synchronous code in the helper class?
(I realise you shouldn't normally use async void, but as the Initialise() method is "fire and forget", I thought it was okay in this scenario).
This line causes a deadlock on the UI thread:
var moreData = _hubProxy.Invoke<BarData>("Method2").Result;
Make ProcessData an async method and await _hubProxy.Invoke inside it:
var moreData = await _hubProxy.Invoke<BarData>("Method2");
Then, await _dataProcessor.ProcessData in your Initialise:
await _dataProcessor.ProcessData(data);
Make sure you don't use .Result or .Wait anywhere else.
Another way of solving it is just this:
public async void Initialise()
{
// Get data from the server - async, as it may be long-running.
var data = await _hubProxy.Invoke<FooData>("Method1").ConfigureAwait(false);
_dataProcessor.ProcessData(data);
}
Note ConfigureAwait(false). In this case the continuation after await will happen on a non-UI thread. This will eliminate the deadlock, but this is not an ideal solution, rather a workaround. Moreover, your logic may require the continuation on the UI thread, for UI access or some thread-safety concerns.
The best solution would be to use both ConfigureAwait(false) (if possible) and avoid blocking with .Result or .Wait, at the same time.