C# Task.Wait Freezin - c#

I have a winform when you click a button it calls a task wait function however it is freezing i'm not sure why.
private async Task GetsData()
{
var connectionString = "mongodb://localhost:27017";
var client = new MongoClient(connectionString);
IMongoDatabase db = client.GetDatabase("mydb");
var collection = db.GetCollection<BsonDocument>("mydata");
using (var cursor = await collection.Find(new
BsonDocument()).ToCursorAsync())
{
while (await cursor.MoveNextAsync())
{
foreach (var doc in cursor.Current)
{
MessageBox.Show(doc.ToString());
}
}
}
}
private void button1_Click(object sender, EventArgs e)
{
try
{
GetsData().Wait();
}
catch(Exception err)
{
MessageBox.Show(err.ToString());
}
}
how can `i stop it from freezing?

Task.Wait() is a blocking action. It will block the GUI thread waiting for the Task/Promise returned from GetsData() to resolve. Meanwhile, async scheduling in a WinForms app will be scheduled against the GUI thread by the SynchronizationContext. Since the GUI thread is blocked by the Wait(), these units of work cannot execute in order to resolve the Task which results in a deadlock.
When using async-await, it is best to use all the way through your code. It is very easy to end up with a deadlock when doing any thread blocking with async-await. Stephen Cleary has some great articles around this when async-await was first introduced.
To resolve, there are a few potential paths but the simplest for this case is likely to turn your event handler in to an async void method and await the GetsData() call instead of using Wait(). Event handlers are the one generally accepted place async void is ideal to use.
private async void button1_Click(object sender, EventArgs e)

Related

Doing synchronous calls when dispatcher's PushFrame is used

I'm working on a plugin for .Net WPF application which uses the frame pushing technique to achieve 'responsible' UI. Each long-running task in its SDK calls the code:
public static void Wait(Task task)
{
DispatcherFrame nestedFrame = new DispatcherFrame();
task.ContinueWith(delegate { return nestedFrame.Continue = false; });
Dispatcher.PushFrame(nestedFrame);
task.Wait();
}
So the typical SDK's method can be emulated by the following code:
private void SdkMethod()
{
var t = Task.Factory.StartNew(() =>
{
Thread.Sleep(1500);
});
Wait(t);
}
It causes a situation when I can not do two synchronous calls to the SDK's methods from the UI thread:
private void OnClick(object sender, RoutedEventArgs e)
{
this.sdk.SdkMethod();
this.sdk.SdkMethod();
}
Is there any way to synchronize calls in such a situation? I cannot modify SDK, only my own calls to it.
If I understood correctly from reading the post and comments, you want to call SdkMethod and have it act synchronously. It's being called without letting you know when it is done.
If it is a void method and it isn't a task, you aren't going to get anything in return. I tried to listen to the Dispatcher Hooks for completion, but that was not helpful.
I'd create an aysnc Task method that has a Task.Delay then await it between calls. That way you aren't interrupting the user, but you still force the call to be paused until you call the second method.
private void OnClick(object sender, RoutedEventArgs e)
{
this.sdk.SdkMethod();
await DelayAsync(3).ConfigureAwait(false);
this.sdk.SdkMethod();
}
private async Task DelayAsync(int seconds)
{
await Task.Delay(seconds * 1000).ConfigureAwait(false);
}
I hope this helps.

Calling an async method with c#5.0

I do some tests with the new asynchronous pattern of C# 5.0 (async/await) I have a problem with understanding how the asynchronous methods are called.
Considering this code :
private async Task<string> DownloadAsync()
{
progress.ProgressChanged += (s, e) =>
{
progressBar1.Value = e.value;
};
return await DownloadSomething(myurl, progress);
}
private async void CallDownloadAsync()
{
string text = await DownloadAsync();
progressBar1.Value = 0;
label1.Text = "Done!";
}
private void button4_Click(object sender, EventArgs e)
{
CallDownloadAsync();
}
So, this code works very well. When I clic the "button4" a downloading task begins and my ProgressBar is updated correctly.
But, I'd like to compact my code a little bit more by removing CallDownloadAsync() method like this :
private void button4_Click(object sender, EventArgs e)
{
new Action(async () =>
{
string result = await Task.Run<string>(() => DownloadAsync());
}).Invoke();
label1.Text = "Running...";
}
So here, I want to directly initiate an action which calls the DownloadAsync method but when I hit my Button4 I have a Cross-thread operation not valid on the progressBar. So I do not understand what is the main difference between the Action() and the call of my CallDownloadAsync() method.
You may find my async/await intro helpful. In particular, an async method does not run on a background thread; Task.Run is used to run something on a background thread, hence the difference in your code.
In general, you should avoid async void, unless you're writing an async event handler. Like this:
private async void button4_Click(object sender, EventArgs e)
{
label1.Text = "Running...";
string result = await DownloadAsync();
progressBar1.Value = 0;
label1.Text = "Done!";
}
The difference is that in former case you call CallDownloadAsync() from UI thread (context).
In the latter case, DownloadAsync() is called from the initiated Task which is generally executed in a different thread created by TPL (Task Parallel Library) out of UI thread or threads created from it.
In WPF, UI components can be accessed only by a dedicated UI thread or (its children) threads created from under it (i.e with the same UI context).

How can I use async to increase WinForms performance?

i was doing some processor heavy task and every time i start executing that command my winform freezes than i cant even move it around until the task is completed. i used the same procedure from microsoft but nothing seem to be changed.
my working environment is visual studio 2012 with .net 4.5
private async void button2_Click(object sender, EventArgs e)
{
Task<string> task = OCRengine();
rtTextArea.Text = await task;
}
private async Task<string> OCRengine()
{
using (TesseractEngine tess = new TesseractEngine(
"tessdata", "dic", EngineMode.TesseractOnly))
{
Page p = tess.Process(Pix.LoadFromFile(files[0]));
return p.GetText();
}
}
Yes, you're still doing all the work on the UI thread. Using async isn't going to automatically offload the work onto different threads. You could do this though:
private async void button2_Click(object sender, EventArgs e)
{
string file = files[0];
Task<string> task = Task.Run(() => ProcessFile(file));
rtTextArea.Text = await task;
}
private string ProcessFile(string file)
{
using (TesseractEngine tess = new TesseractEngine("tessdata", "dic",
EngineMode.TesseractOnly))
{
Page p = tess.Process(Pix.LoadFromFile(file));
return p.GetText();
}
}
The use of Task.Run will mean that ProcessFile (the heavy piece of work) is executed on a different thread.
You can also do this by starting your task in new thread.
Just use Thread.Start or Thread. ParameterizedThreadStart
See these for your reference:
http://msdn.microsoft.com/en-us/library/system.threading.parameterizedthreadstart.aspx
Start thread with parameters
You could use BackgroundWorker component.

How do I force a task to run on the UI thread?

Original message below. Let me try and explain with more details why I am asking for this.
I have a page that listens to the Share charm request:
void Page_Loaded(object sender, RoutedEventArgs e)
{
m_transferManager = Windows.ApplicationModel.DataTransfer.DataTransferManager.GetForCurrentView();
m_transferManager.DataRequested += TransferManager_DataRequested;
}
When the event fires (TransferManager_DataRequested) it does not fire on the UI thread:
void TransferManager_DataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{
var data = args.Request.Data;
// More related stuff omitted - not important.
data.SetDataProvider(StandardDataFormats.Bitmap, GetImage_DelayRenderer);
}
Now, when GetImage_DelayRender is called, it also does not get called on the UI thread. However, in it, I need to do a bunch of UI related things. Specifically, I need to call a method that only works on the UI (it's a method I use elsewhere and I want to reuse it's logic). The method is called GetImageAsync and it needs to run on the UI because it does a bunch of interactions with WriteableBitmap. It also does a bunch of async operations (such as writing to stream etc) which is why it's async. I block the UI on GetImageAsync() for as short a time as I can.
Here's what GetImage_DelayRender looks like:
private async void GetImage_DelayRenderer(DataProviderRequest request)
{
var deferral = request.GetDeferral();
await Dispatcher.RunTask(async () => // RunTask() is an extension method - described in the original question below.
{
try
{
var bitmapStream = await GetImageAsync();
request.SetData(RandomAccessStreamReference.CreateFromStream(bitmapStream));
}
catch
{
}
});
deferral.Complete();
}
What I want to know is, what is the most correct way to achieve the call to Dispatcher.RunTask() above (which is my hack extension method).
----- START ORIGINAL MESSAGE -------
Say I have the following task:
private async Task SomeTask()
{
await Task.Delay(1000);
// Do some UI and other stuff that may also be async
}
Edit (Clarification): I do not want to block the UI. The task I want to execute (even in the example, if you read it) WILL NOT block the UI. I just want the task to run in the context of the UI for it's synchronous portions.
I want to run this on code on the UI thread as an Async operation. Dispatcher.RunXXX() methods take an action, which means they will run the action and notify you when they are done. That's not good enough. I need the entire task to run on the UI thread (as it would have executed had I run it from the UI thread) and then, when done, to notify me back.
The only way I could think of, is to use the Dispatcher.RunXXX() methods to execute an anon delegate that sets a local variable in my method to the task and then awaits that...
public async static Task RunTask(this CoreDispatcher dispatcher, Func<Task> taskGiver)
{
Task task = null;
await dispatcher.RunAsync(() => task = taskGiver());
await task;
}
This looks pretty damn ugly. Is there a better way of doing it?
Edit2: Guys - read this code - if I execute the first code block above using the RunTask() hack I have, IT WILL NOT BLOCK THE UI on the Task.Delay()...
I want to run this on code on the UI thread as an Async operation.
Then just run it:
async void MyEventHandler(object sender, ...)
{
await SomeTask();
}
Update:
I'm not sure this is a "legal" operation, but you can schedule that method to run on the UI thread by capturing the CoreDispatcher while the UI is active and later calling RunAsync:
private async void GetImage_DelayRenderer(DataProviderRequest request)
{
var deferral = request.GetDeferral();
Task task = null;
await coreDispatcher.RunAsync(() => { task = SomeTask(); });
await task;
deferral.Complete();
}
I don't have time to do a complete solution, so hopefully you will still find this useful...
First, as others have pointed out, you cannot run something on the UI thread and not have it block the UI thread. End of discussion. What you are saying you need is something to run on a non-UI thread and periodically notify the UI thread that there are updates that need to be processed.
To accomplish this, you need something like this...
public class LongTask
{
public event EventHandler MyEvent;
public void Execute()
{
var task = Task.Factory.StartNew(() =>
{
while (true)
{
// condition met to notify UI
if (MyEvent != null)
MyEvent(this, null);
}
});
}
}
In your UI then, do something like...
private void button_Click(object sender, RoutedEventArgs e)
{
var test = new LongTask();
test.MyEvent += test_MyEvent;
test.Execute();
}
void test_MyEvent(object sender, EventArgs e)
{
Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
test.Text += " bang ";
});
You could obviously implement this in a much cleaner fashion using something like MVVM, but this is the basic idea.
}
I've done it like this:
public static Task<string> GetResultAsync()
{
return Task<string>.Factory.StartNew(() => GetResultSync());
}
In UI:
private async void test()
{
string result = await GetResultAsync();
// update UI no problem
textbox.Text = result;
}

Why thread in background is not waiting for task to complete?

I am playing with async await feature of C#. Things work as expected when I use it with UI thread. But when I use it in a non-UI thread it doesn't work as expected. Consider the code below
private void Click_Button(object sender, RoutedEventArgs e)
{
var bg = new BackgroundWorker();
bg.DoWork += BgDoWork;
bg.RunWorkerCompleted += BgOnRunWorkerCompleted;
bg.RunWorkerAsync();
}
private void BgOnRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs runWorkerCompletedEventArgs)
{
}
private async void BgDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
{
await Method();
}
private static async Task Method()
{
for (int i = int.MinValue; i < int.MaxValue; i++)
{
var http = new HttpClient();
var tsk = await http.GetAsync("http://www.ebay.com");
}
}
When I execute this code, background thread don't wait for long running task in Method to complete. Instead it instantly executes the BgOnRunWorkerCompleted after calling Method. Why is that so? What am I missing here?
P.S: I am not interested in alternate ways or correct ways of doing this. I want to know what is actually happening behind the scene in this case? Why is it not waiting?
So, BgDoWork is called on a background thread by the BackgroundWorker
It calls Method, which starts the loop and calls http.GetAsync
GetAsync returns a Task and continues it's work on another thread.
You await the Task which, because the Task has not completed, returns from Method
Similarly, the await in BgDoWork returns another Task
So, the BackgroundWorker sees that BgDoWork has returned and assumes it has completed.
It then raises RunWorkerCompleted
Basically, don't mix BackgroundWorker with async / await!
Basically, there are two problems with your code:
BackgroundWorker wasn't updated to work with async. And the whole point of async methods is that they actually return the first time they await something that's not finished yet, instead of blocking. So, when your method returns (after an await), BackgroundWorker thinks it's completed and raises RunWorkerCompleted.
BgDoWork() is an async void method. Such methods are “fire and forget”, you can't wait for them to complete. So, if you run your method with something that understands async, you would also need to change it to async Task method.
You said you aren't looking for alternatives, but I think it might help you understand the problem if I provided one. Assuming that BgDoWork() should run on a background thread and BgOnRunWorkerCompleted() should run back on the UI thread, you can use code like this:
private async void Click_Button(object sender, RoutedEventArgs e)
{
await Task.Run((Func<Task>)BgDoWork);
BgOnRunWorkerCompleted();
}
private void BgOnRunWorkerCompleted()
{
}
private async Task BgDoWork()
{
await Method();
}
Here, Task.Run() works as an async-aware alternative to BackgroundWorker (it runs the method on a background thread and returns a Task that can be used to wait until it actually completes). After await in Click_Button(), you're back on the UI thread, so that's where BgOnRunWorkerCompleted() will run. Click_Button() is an async void method and this is pretty much the only situation where you would want to use one: in an event handler method, that you don't need to wait on.
I think you need some reason for the background thread to stay alive while it's waiting for Method() to complete. Having an outstanding continuation is not enough to keep a thread alive, so your background worker terminates before Method() completes.
You can prove this to yourself by changing your code so that the background thread does a Thread.Sleep after the await Method(). That's almost certainly not the real behaviour you want, but if the thread sleeps for long enough you'll see Method() complete.
Following is how DoWork is raised and handled. (code retrieved using Reflector tool).
private void WorkerThreadStart(object argument)
{
object result = null;
Exception error = null;
bool cancelled = false;
try
{
DoWorkEventArgs e = new DoWorkEventArgs(argument);
this.OnDoWork(e);
if (e.Cancel)
{
cancelled = true;
}
else
{
result = e.Result;
}
}
catch (Exception exception2)
{
error = exception2;
}
RunWorkerCompletedEventArgs arg = new RunWorkerCompletedEventArgs(result, error, cancelled);
this.asyncOperation.PostOperationCompleted(this.operationCompleted, arg);
}
protected virtual void OnDoWork(DoWorkEventArgs e)
{
DoWorkEventHandler handler = (DoWorkEventHandler) base.Events[doWorkKey];
if (handler != null)
{
handler(this, e);
}
}
There is no special handling to wait for async method. (using async/await keyword).
To make it wait for async operation, following changes are required.
async private void WorkerThreadStart(object argument)
await this.OnDoWork(e);
async protected virtual void OnDoWork(DoWorkEventArgs e)
await handler(this, e);
But then, BackgroundWorker is .net 2.0 construct, and async/await are .net 4.5. it will be full circle, if any one of these uses other construct.
You can't await an event handler because it doesn't return anything to await on. From the documentation of the async keyword:
The void return type is used primarily to define event handlers, where a void return type is required. The caller of a void-returning async method can't await it and can't catch exceptions that the method throws.
By adding the async keyword to the BgDoWork event handler you are instructing .NET to execute the handler asynchronously and return as soon as the first yielding operation is encountered. In this case, this happens after the first call to http.GetAsync

Categories