Callback for task, why does the UI thread block - c#

I have the following piece of code:
public static async Task<SqlConnection> OpenSqlConnectionAsync()
{
if (_SqlConnection == default(SqlConnection))
{
_SqlConnection = new SqlConnection();
}
if (_SqlConnection.State == ConnectionState.Closed || _SqlConnection.State == ConnectionState.Broken)
{
_SqlConnection.ConnectionString = SqlConnectionStuff.GetConnectionString;
Task ConnectionTask = _SqlConnection.OpenAsync();
await ConnectionTask.ContinueWith((PreviousTask) =>
{
}
);
if (_SqlConnection.State == ConnectionState.Open)
{
MainWindow.Instance.lblCursorPosition.Dispatcher.Invoke(() => { MainWindow.Instance.lblCursorPosition.Text = "Connection opened!"; });
}
else
{
MainWindow.Instance.lblCursorPosition.Dispatcher.Invoke(() => { MainWindow.Instance.lblCursorPosition.Text = "Connection not opened!"; });
}
}
return GetSqlConnection;
}
In a separate class with the hopefully describing name SqlConnectionStuff... (no worries it will get changed soon ;P)
And down in my Window code there's is written the following:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
SqlConnectionStuff.OpenSqlConnectionAsync().Wait();
}
So when Invoking this using the Wait method behind the Task, stops the execution at the ContinueWith callback # the OpenSqlConnectionAsync method.
The window freezes. It doesn't seem to finish and it looks like the UI thread is getting blocked, which makes sense from my rudimentary insights into the behaviour of the threads. It is not necessary for it to block at all but this method has to be executed before anything else will work so it won't matter at all if the user input is locked as long as the connection is established.
My interest now would be, why if I remove the Wait() instruction, the await on the callback seems to be executed flawlessly without getting stuck (as it is an empty instruction which can't fail obv.), and afterwards the information for the user is displayed in the UI.

This code:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
SqlConnectionStuff.OpenSqlConnectionAsync().Wait();
}
...specifically the Wait() blocks the UI thread from executing. By the way, calling an async method then explicitly blocking on it by calling Wait defeats the purpose of async/await by the way. It's like spinning up a thread only to Join on it. There are times when its ok to do so like when the signature of the method can't be changed to async (as in console apps Main methods prior to C# 7)
Meanwhile the following code attempts to synchonously thread marshal from whatever is the current thread to the UI thread in order to have the UI thread update the lblCursorPosition.Text property.
MainWindow.Instance.lblCursorPosition.Dispatcher.Invoke(() =>
{ MainWindow.Instance.lblCursorPosition.Text = "Connection opened!"; });
Unforunately as we already mentioned, the UI thread is already busy waiting for OpenSqlConnectionAsync to complete. So now you have a case of both ends waiting on the other. You have a deadlock.
A fix would be to change the method signature like so and call await:
private async void Window_Loaded(object sender, RoutedEventArgs e) // <-- note async
{
// await synchronously
await SqlConnectionStuff.OpenSqlConnectionAsync(); // await here. No Wait()
}
You could fix it another way by changing Invoke to BeginInvoke. The latter posts the action asynchronously to the UI thread. The net effect would be OpenSqlConnectionAsync would return the GetSqlConnection; the UI thread would resume following the Wait(); and later process the updating of the Label.
MainWindow.Instance.lblCursorPosition.Dispatcher.BeginInvoke(() =>
{ MainWindow.Instance.lblCursorPosition.Text = "Connection opened!"; });

Related

How do I marshal an event from Task.Run back to the UI thread?

I have a method that is "partially" async, meaning that one code path runs async and the other runs synchronously. I can't currently make the synchronous part async, although I may be able to in the future.
public async Task UpdateSomethingAsync(){
if (ConditionIsMet){
await DoSomethingAsync;
}else{
DoSomethingSynchronous;
}
}
Both DoSomethingAsync and DoSomethingSynchronous are I/O bound. Calling this method from the Winforms UI thread with "await" causes it to block the UI thread if the Synchronous path is taken, which is to be expected.
private async void MyDropDownBox_DropDownClosed(object sender, EventArgs e)
{
//This blocks if the DoSomethingSynchronous path is taken, causing UI to
//become unresponsive.
await UpdateSomethingAsync();
}
So off to Stephen Cleary's blog I go. His suggestion (although for CPU bound code instead of I/O bound) is to run the method with Task.Run, as if it were completely synchronous, while documenting that the method is "partially" async. However, events raised by DoSomethingSynchronous now cause an exception, I believe due to the fact that they are now on a different thread from the UI.
private async void MyDropDownBox_DropDownClosed(object sender, EventArgs e)
{
//This no longer blocks, but events will not marshal back to UI Thread
//causing an exception.
await Task.Run(()=> UpdateSomethingAsync());
}
How can this be fixed?
Don't update the UI, or any model bound to the UI inside of UpdateSomethingAsync or any of the methods that it calls. Create a class that will hold the data required to update your UI, and return an instance of that class from UpdateSomethingAsync.
DoSomethingAsync will return a Task<ThatClassYouCreated> and DoSomethingSynchronous just returns an instance of ThatClassYouCreated. Then, back in MyDropDownBox_DropDownClosed after you await UpdateSomethingAsync, use the instance returned by UpdateSomethingAsync to update your UI or your model.
public class UpdatedInformation
{
public int UpdateId { get; set; }
public string UpdatedName { get; set; }
public DateTimeOffset Stamp { get; set; }
// etc, etc...
}
public class YourForm : Form
{
private async Task<UpdatedInformation> DoSomethingAsync()
{
var result = new UpdatedInformation();
// Something is awaited...
// Populate the properties of result.
// Do not modify your UI controls. Do not modify the model bound to those controls.
return result;
}
private UpdatedInformation DoSomethingSynchronous()
{
var result UpdatedInformation();
// Populate the properties of result.
// Do not modify your UI controls. Do not modify the model bound to those controls.
return result;
}
private async Task<UpdatedInformation> UpdateSomethingAsync()
{
if (ConditionIsMet)
{
return await DoSomethingAsync();
}
else
{
return await Task.Run(DoSomethingSynchronous);
}
}
private async void MyDropDownBox_DropDownClosed(object sender, EventArgs e)
{
var updatedInformation = await UpdateSomethingAsync();
// Now use updatedInformation to update your UI controls, or the model bound to
// your UI controls.
model.Id = updatedInformation.UpdateId;
// etc...
}
}
In your event handler, you can use Invoke() to update the UI like this:
private void someEventHandler() // <- it might have params
{
// ... possibly some other code that does NOT update the UI ...
this.Invoke((MethodInvoker)delegate {
// ... it's safe to update the UI from in here ...
});
// ... possibly some other code that does NOT update the UI ...
}
I don't know who keeps doing it, but my comments below this post keep getting deleted.
This answers the TITLE of the question, which was:
How do I marshal an event from Task.Run back to the UI thread?
When you receive an event from a different thread, this is a perfectly valid way of updating the UI.
Sicne you state that "[..] DoSomethingSynchronous [is] I/O bound" you could also make it async by wrapping the IO bound operation within DoSomethingSynchronous in a Task.Run.
So if DoSomethingSynchronous is something like
public void DoSomethingSynchronous(...)
{
// some UI work
// blocking sysnchornous IO operation
var res = IoOperation();
// some more UI work
}
you could rewrite it to.
public async Task DoSomethingSynchronous(...)
{
// some UI work
// no-UI-Thread blocking IO operation
var res = await Task.Run(() => IoOperation()).ConfigureAwait(true);
// some more UI work
}
the .ConfigureAwait(true) could maybe omited but ensures that the code after the await will be scheduled in the orignal sync-context i.e. the UI-Thread.
You then obviously need to rename the method and such, but this will make the code more maintainable if you someday can use a true asycn IO in DoSomethingSynchronous
Since UpdateSomethingAsync needs to access the UI context, it shouldn't be wrapped in a Task.Run call. (You should very rarely, need to call an async method from Task.Run, usually only if the method is implemented incorrectly and you can't fix it.)
Instead DoSomethingSynchronous should be the thing you call from Task.Run. After all, the purpose of that method is to asynchronously run a synchronous method in a thread pool thread. So only use it for the synchronous method you want run in a thread pool thread, not the (supposedly) asynchronous method that needs to access the UI context.
WinUI 3 respects the below method.
DispatcherQueue.TryEnqueue(() =>
{
//Code to Update the UI
});
Figured I'd answer this myself after some more research. Most of the other answers are correct in some way, but don't necessarily explain the whole deal in one go, so I'll try to sum up here.
This first snippet from the question works event wise, but blocks if the Synchronous path in UpdateSomethingAsync is taken. Events work because "await" automatically captures the SynchronizationContext (this is key) for the UI thread, such that any events raised from UpdateSomethingAsync are marshalled back to the UI, via the SynchronizationContext. This is just the normal way of using async/await:
private async void MyDropDownBox_DropDownClosed(object sender, EventArgs e)
{
//This blocks if the DoSomethingSynchronous path is taken, causing UI to
//become unresponsive, but events propagate back to the UI correctly.
await UpdateSomethingAsync();
}
Task.Run works in much the same way, if you aren't using it to run an async method. In other words, this works without blocking and will still send events to the UI thread, because UpdateSomethingAsync is replaced with a Synchronous method. This is just the normal usage of Task.Run:
private async void MyDropDownBox_DropDownClosed(object sender, EventArgs e)
{
//UpdateSomethingAsync is replaced with a Synchronous version, and run with
// Task.Run.
await Task.Run(UpdateSomethingSynchronously());
}
However, the original code in question is Async, so the above doesn't apply. The question poses the following snippet as a possible solution, but it errors out with an Illegal Cross Thread call to the UI when an event is raised, because we are using Task.Run to call an Async method, and for some reason this does not set the SynchronizationContext:
private async void MyDropDownBox_DropDownClosed(object sender, EventArgs e)
{
//This no longer blocks, but events raised from UpdateSomethingAsync
//will cause an Illegal Cross Thread Exception to the UI, because the
//SyncrhonizationContext is not correct. Without the SynchronizationContext,
//events are not marshalled back to the UI thread.
await Task.Run(()=> UpdateSomethingAsync());
}
What does seem to work is to use Task.Factory.StartNew to assign the UI SynchronizationContext to the Task using TaskScheduler.FromCurrentSynchronizationContext, like so:
private async void MyDropDownBox_DropDownClosed(object sender, EventArgs e)
{
//This doesn't block and will return events to the UI thread sucessfully,
//because we are explicitly telling it the correct SynchronizationContext to use.
await Task.Factory.StartNew(()=> UpdateSomethingAsync(),
System.Threading.CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext);
}
What also works, and is very simple but "lies" a little to the caller, is to simply wrap DoSomethingSynchronous in Task.Run:
public async Task UpdateSomethingAsync(){
if (ConditionIsMet){
await DoSomethingAsync;
}else{
await Task.Run(DoSomethingSynchronous);
}
}
I consider this a little bit of a lie, because the method is not really fully Async in the sense that it spins off a Thread Pool thread, but may never pose an issue to a caller.
Hopefully this makes sense. If any of this is proven incorrect please let me know, but this is what my testing has uncovered.

C# - ' Dispatcher.BeginInvoke(new Action(() => ' doesn't work within Winforms. CS0120 [duplicate]

I am trying to understand better how can I update a windows forms progress bar from an async operation but I am getting some unexpected behavior from that.
Basically I am having a button which should after is being clicked to update a progress bar and then set it back to 0 once the progress bar gets 100% updated.
This is my code:
private async void button1_Click(object sender, EventArgs e)
{
await CallMethodAsync().ContinueWith((prevTask) =>
{
prevTask.Wait();
progressBar1.Invoke(new Action(() => { progressBar1.Value = 0; }));
});
}
private static async Task ExecuteMethodAsync(IProgress<double> progress = null)
{
double percentComplete = 0;
bool done = false;
while (!done)
{
if (progress != null)
{
progress.Report(percentComplete);
}
percentComplete += 10;
if(percentComplete == 100)
{
done = true;
}
}
}
private async Task CallMethodAsync()
{
var progress = new Progress<double>();
progress.ProgressChanged += (sender, args) => { progressBar1.Increment(10); };
await ExecuteMethodAsync(progress);
}
Having this implementation the progress bar is not being updated at all even if I call "Wait()" on the operation that should update the value of the progress bar.
If i remove this part of code:
progressBar1.Invoke(new Action(() => { progressBar1.Value = 0; }));
the progress bar gets updated but it remains all the time like that, and I want to set it back to 0 once it was entirely filled so that I can update it again when I click again the button.
Could someone please explain me what am I doing wrong ?
One of the reasons async-await syntax was invented because it was difficult to follow the sequence of instructions when tasks were concatenated using functions like ContinueWith.
If you use async-await it is seldom necessary to use statements like ContinueWith. After an await, the thread already continues with the statements after the await.
If the button is clicked, you want to call ExcecuteMethodAsync. This function takes an IProgress, because it wants to report progress regularly. You want to call this function asynchronously, so whenever the function has to wait for something, it doesn't really wait, but returns control to you so you could do other things instead of really waiting, until you encounter an await, in which case your caller continues processing until he encounters an await, etc.
The nice thing with async-await is that the thread that continues after your call to an async function has the same context as the calling thread. This means that you can regard it as your original thread. No InvokeRequired, no need to protect data with mutexes etc.
Your function could be simplified as follows:
async Task CallMethodAsync()
{
var progress = new Progress<double>();
progress.ProgressChanged += OnProgressReported;
await ExecuteMethodAsync(progress);
}
private void OnProgressReported(object sender, ...)
{
// because this thread has the context of the main thread no InvokeRequired!
this.progressBar1.Increment(...);
}
private async void button1_Click(object sender, EventArgs e)
{
await CallMethodAsync();
}
So when the button is clicked, CallMethodAsync is called. This function will create A Progress object and subscribes on its Report event. Note that this is still your UI-thread. Then it calls ExecuteMethodAsync, which will regularly raise event Report, which is handled by OnProgressReported.
Because ExecuteMethodAsync is async, you can be sure there is somewhere an await in it. This means that whenever it has to await, control returns to the caller, which is CallMethodAsync, until is encounters an await, which in this case is immediately.
Control goes up the call stack to the caller, which is button1_click, where it immediately encounters an await, so control goes up the call stack, etc.
All these controls have the same context: it is as if they are the same thread.
An article that helped me a lot to understand async-await is this interview with Eric Lippert. Search somewhere in the middle for async await
Another articel that helped me a lot to learn good practices were this article by the ever so helpful Stephen Cleary and Async/Await - Best Practices in Asynchronous Programming also by Stephen Cleary
Your issue is happening because ExecuteMethodAsync(...) is not actually asynchronous.
Add the following before the while loop to make it asynchronous
await Task.Delay(1);
or enclose some synchronous portion of code (e.g. the while loop) into a:
await Task.Run(() => { ... });
or (the best one), add the following at the beginning of the function:
await Task.Yield(); // Make us async right away

EventWaitHandle waitOne() causes my worker thread to suspend until it has timed out

I am using a EventWaitHandle() handler. This handler is called in a ButtonClick event that waits for 10 seconds. There is another worker thread which upon receiving some data call Set() on the handler.
Problem is the WaitOne() returns false after the timeout occurs. The worker thread doesnt run and looks like its suspended, hence Set() is not called. Once the timeout is over, my worker thread resumes and Set() method is called.
To verify I tried without the EventWaitHandle() to check if my worker thread actually takes 10 seconds of time, but it didnt, and Set() method had hit immediately.
I am not sure why the worker thread runs after the timeout has occurred in the
I am new to C#. Thanks in advance
MainWindow.xaml.cs
public static EventWaitHandle autoResetEvent = new EventWaitHandle(false, EventResetMode.AutoReset);
XYZDialogBox.cs
private void BtnConnect_Click(object sender, RoutedEventArgs e)
{
MainWindow.autoResetEvent.Reset();
if (!MainWindow.autoResetEvent.WaitOne(10000))
{
//Line number details is not received from Service
MessageBox.Show("Timeout");
//now disconnect and exit
strCommand = "#cmddisconnect " + tbIPAddress.Text + " #";
tcpClient.AddCommandAsync(strCommand);
return;
}
}
ABC.cs
public void ABC(ref string strData)
{
while(strData != "")
{
//do something
MainWindow.autoResetEvent.Set();
}
}
Using the async await pattern based on your code:
private async void BtnConnect_Click(object sender, RoutedEventArgs e)
{
// await frees up the main thread but halts execution of this method until finished.
var result = await Task.Run(() =>
{
//Do something that takes time.
// This is now in another thread.
return MyService.ServiceCall(arg);
});
// use result here synchronously.
}
As an aside the example here is very rudimentary case of using the async await pattern. Ideally your service would have a library that implements an async method call that returns an awaitable task. That would look something like this.
private async void BtnConnect_Click(object sender, RoutedEventArgs e)
{
bool success = await MyService.ServiceCallAsync(args); // async service call.
if(success)
{
// handle
return;
}
// an error occurred.
}

WPF Progress bar working but blocked in UI thread even using async

I am trying to implement an indeterminate progress bar into my program. I'm new to threading, but as far as I know one of the best options here is to add an async method, and await the "heavy" function to perform its results. So I wrote this:
public void Window_Loaded(object sender, RoutedEventArgs e)
{
firstLoad();
}
private async void firstLoad()
{
LW.Title = "Loading...";
LW.Show();
filterTextBox.Text = defaultSearch;
await Task.Run(() => InitializeFilter());
}
private void InitializeFilter()
{
//Asynchronous???
Dispatcher.BeginInvoke(new Action(() => {
//... some lines of code that takes some time to run.
dataGrid.ItemContainerGenerator.StatusChanged += new EventHandler(closeLoadingWindow);
}));
private void closeLoadingWindow(object sender, EventArgs e)
{
if (LW != null)
{
LW.closable = true;
LW.Close();
}
}
firstLoad runs when the window is loaded, showing an indeterminate LW loadingWindow, and running the InitializeFilter() method (the heavy one). Finally, when the grid is populated and loaded, an event fires, allowing the LW window to be closed and closing it (if I didn't make it unclosable, a funny user could just close it clicking or using F4, which is not nice).
The system is working properly and everything works as expected regarding time frames, but the loading bar is frozen, not showing progress. The same LW bar works in the MainWindow with a similar set up What am I missing? Thanks in advance!
as far as I know one of the best options here is to add an async method, and await the "heavy" function to perform its results
The best option is to use Task.Run to move the heavy processing to the thread pool, and use await to retrieve its results.
The code as it currently stands uses Task.Run to move to the thread pool and then immediately turns around and uses Dispatcher to move back to the UI thread before doing the heavy processing. Thus, it's blocking the UI thread.
what this particular DataGrid displays is a CollectionView, which is not thread-safe.
Right, you can't update data-bound objects from a thread pool thread.
The best solution is to separate the heavy processing from the UI updates, something like this:
public async void Window_Loaded(object sender, RoutedEventArgs e)
{
await firstLoadAsync();
}
private List<FilterType> InitializeFilter()
{
//... some lines of code that takes some time to run.
}
private async Task firstLoadAsync()
{
LW.Title = "Loading...";
LW.Show();
filterTextBox.Text = defaultSearch;
var filterData = await Task.Run(() => InitializeFilter()); // Get the plain data on a background thread
myCollectionView = new CollectionView(filterData); // Update the UI
if (LW != null)
{
LW.closable = true;
LW.Close();
}
}
do not use your dispatcher. Microsoft had the foresight to use it's magic (SynchronizationContext) to be able to update the UI thread in a method that is being executed in an async context. This is demonstrated in their async/await example found here
while under previous/other circumstances, you would have to either marshal back to the main (UI) thread to update the UI thread, or wait until completed and retrieve the results from objects who share state. Since you are using async/await then you should be fine to not use the dispatcher, and update the UI directly.

How to run and interact with an async Task from a WPF gui

I have a WPF GUI, where I want to press a button to start a long task without freezing the window for the duration of the task. While the task is running I would like to get reports on progress, and I would like to incorporate another button that will stop the task at any time I choose.
I cannot figure the correct way to use async/await/task. I can't include everything I've tried, but this is what I have at the moment.
A WPF window class :
public partial class MainWindow : Window
{
readonly otherClass _burnBabyBurn = new OtherClass();
internal bool StopWorking = false;
//A button method to start the long running method
private async void Button_Click_3(object sender, RoutedEventArgs e)
{
Task slowBurn = _burnBabyBurn.ExecuteLongProcedureAsync(this, intParam1, intParam2, intParam3);
await slowBurn;
}
//A button Method to interrupt and stop the long running method
private void StopButton_Click(object sender, RoutedEventArgs e)
{
StopWorking = true;
}
//A method to allow the worker method to call back and update the gui
internal void UpdateWindow(string message)
{
TextBox1.Text = message;
}
}
And a class for the worker method:
class OtherClass
{
internal Task ExecuteLongProcedureAsync(MainWindow gui, int param1, int param2, int param3)
{
var tcs = new TaskCompletionSource<int>();
//Start doing work
gui.UpdateWindow("Work Started");
While(stillWorking)
{
//Mid procedure progress report
gui.UpdateWindow("Bath water n% thrown out");
if (gui.StopTraining) return tcs.Task;
}
//Exit message
gui.UpdateWindow("Done and Done");
return tcs.Task;
}
}
This runs, but the WPF function window is still blocked once the worker method starts.
I need to know how to arrange the async/await/task declarations to allow
A) the worker method to not block the gui window
B) let the worker method update the gui window
C) allow the gui window to stop interrupt and stop the worker method
Any help or pointers are much appreciated.
Long story short:
private async void ButtonClickAsync(object sender, RoutedEventArgs e)
{
// modify UI object in UI thread
txt.Text = "started";
// run a method in another thread
await HeavyMethodAsync(txt);
// <<method execution is finished here>>
// modify UI object in UI thread
txt.Text = "done";
}
// This is a thread-safe method. You can run it in any thread
internal async Task HeavyMethodAsync(TextBox textBox)
{
while (stillWorking)
{
textBox.Dispatcher.Invoke(() =>
{
// UI operation goes inside of Invoke
textBox.Text += ".";
// Note that:
// Dispatcher.Invoke() blocks the UI thread anyway
// but without it you can't modify UI objects from another thread
});
// CPU-bound or I/O-bound operation goes outside of Invoke
// await won't block UI thread, unless it's run in a synchronous context
await Task.Delay(51);
}
}
Result:
started....................done
You need to know about (1) how to write async code (2) how to run UI operations in another thread and (3) how to cancel a task.
I'm not getting into (3) cancellation mechanism in this post. Just know that you can create a CancellationTokenSource, which gives you a CancellationToken which you can pass into any method. You cancel the source, all tokens will know.
async and await:
Basics of async and await
You can only await in an async method.
You can only await an awaitable object (i.e. Task, ValueTask, Task<T>, IAsyncEnumerable<T>, etc.) These objects wrap around the return type of an async method and await keyword unwraps them. (see Wrapping and Unwrapping section)
Asynchronous method names should always end with Async to increase readability and to prevent mistakes.
// Synchronous method:
TResult MethodName(params) { }
// Asynchronous method:
async Task<TResult> MethodNameAsync(params) { }
The magic of async and await
The async-await syntactic feature, uses a state-machine to let the compiler give up and take back the control over the awaited Task in an async method.
The execution waits at await for the task to finish and returns back its results, without blocking the main thread.
Task.Run queues a Task in the thread pool. (Unless the it's a pure operation.)
i.e. The async method does not run in another thread. async and await by themselves don't have anything to do with thread creation.
So
When you run a Task (e.g. Task.Run(action)) you (re)use a thread for that action. And you can put that task in an async method to control its flow. By putting async in the method signature you tell the compiler to use state-machine to control the flow of that method (this does not mean threading at all). And by awaiting the task you prevent the execution flow within that method from moving past the awaited statement without blocking UI thread. If you want to pass the flow onto the caller then the async method itself can become a Task so you'll be able to cascade the same pattern out into the caller and so forth:
async Task Caller() { await Method(); }
async Task Method() { await Inner(); }
async Task Inner() { await Task.Run(action); }
The event handler looks like the code below.
Two possible cases for presense of async in the signature of ExecuteLongProcedure (case 1 and 2) and MyButton_ClickAsync (case A and B) are explained:
private async void MyButton_ClickAsync(object sender, RoutedEventArgs e)
{
//queue a task to run on threadpool
// 1. if ExecuteLongProcedure is a normal method and returns void
Task task = Task.Run(()=>
ExecuteLongProcedure(this, intParam1, intParam2, intParam3)
);
// or
// 2. if ExecuteLongProcedure is an async method and returns Task
Task task = ExecuteLongProcedureAsync(this, intParam1, intParam2, intParam3);
// either way ExecuteLongProcedure is running asynchronously here
// the method will exit if you don't wait for the Task to finish
// A. wait without blocking the main thread
// -> requires MyButton_ClickAsync to be async
await task;
// or
// B. wait and block the thread (NOT RECOMMENDED AT ALL)
// -> does not require MyButton_ClickAsync to be async
task.Wait();
}
Async method return types:
Suppose you have the following declaration:
private async ReturnType MethodAsync() { ... }
If ReturnType is Task then await MethodAsync(); returns void
If ReturnType is Task<T> then await MethodAsync(); returns a value of type T
This is called Unwrapping, see the next section (Wrapping and Unrwapping).
If ReturnType is void you can't await it
If you try writing await MethodAsync();, you will get a compile error saying:
cannot await void
You can only fire and forget i.e. just call the method normally: MethodAsync(); and then go on with your life.
The MethodAsync execution will be synchronous, however since it has async it will allow you to take advantage of the magic, i.e. you can write await task within the method to control the flow of execution.
This is how WPF handles your button click event handler, obviously because your event handler returns void.
The return type of an async method must be void, Task, Task<T>, a task-like type, IAsyncEnumerable<T>, or IAsyncEnumerator<T>
Wrapping and Unrwapping:
Wrapping:
async methods wrap their return values in a Task.
E.g., this method wraps a Task around an int and returns it:
// async Task<int>
private async Task<int> GetOneAsync()
{
int val = await CalculateStuffAsync();
return val;
// returns an integer
}
Unwrapping:
To retrieve or unwrap the value which is wrapped inside a Task<>:
asynchronous option: await
synchronous option: task.Result or task.GetAwaiter().GetResult() or task.WaitAndUnwrapException() or read How to call asynchronous method from synchronous method in C#?
e.g. await unwraps the int out of the Task:
Task<int> task = GetOneAsync();
int number = await task;
//int <- Task<int>
Different ways to wrap and unwrap:
private Task<int> GetNumber()
{
Task<int> task;
task = Task.FromResult(1); // the correct way to wrap a quasi-atomic operation, the method GetNumber is not async
task = Task.Run(() => 1); // not the best way to wrap a number
return task;
}
private async Task<int> GetNumberAsync()
{
int number = await Task.Run(GetNumber); // unwrap int from Task<int>
// bad practices:
// int number = Task.Run(GetNumber).GetAwaiter().GetResult(); // sync over async
// int number = Task.Run(GetNumber).Result; // sync over async
// int number = Task.Run(GetNumber).Wait(); // sync over async
return number; // wrap int in Task<int>
}
Still confused? Read async return types on MSDN.
To unwrap a task result, Always try to use await instead of .Result otherwise there will be no asynchronous benefit but only asynchronous disadvantages. The latter is called "sync over async".
Note:
await is a asynchronous and is different from task.Wait() which is synchronous. But they both do the same thing which is waiting for the task to finish.
await is a asynchronous and is different from task.Result which is synchronous. But they both do the same thing which is waiting for the task to finish and unwrapping and returning back the results.
To have a wrapped value, you can always use Task.FromResult(1) instead of creating a new thread by using Task.Run(() => 1).
Task.Run is newer (.NetFX4.5) and simpler version of Task.Factory.StartNew
WPF GUI:
This is where I explain how to run UI operations in another thread.
Blocking:
First thing you need to know about WPF async event handlers is that the Dispatcher will provide a synchronization context. Explained here
CPU-bound or IO-bound operations such as Sleep and task.Wait() will block and consume the thread even if they are called in a method with async keyword. but await Task.Delay() tells the state-machine to stop the flow of execution on the thread so it does not consume it; meaning that the thread resources can be used elsewhere:
private async void Button_Click(object sender, RoutedEventArgs e)
{
Thread.Sleep(1000);//stops, blocks and consumes threadpool resources
await Task.Delay(1000);//stops without consuming threadpool resources
Task.Run(() => Thread.Sleep(1000));//does not stop but consumes threadpool resources
await Task.Run(() => Thread.Sleep(1000));//literally the WORST thing to do
}
Thread Safety:
If you have to access GUI asynchronously (inside ExecuteLongProcedure method), invoke any operation which involves modification to any non-thread-safe object. For instance, any WPF GUI object must be invoked using a Dispatcher object which is associated with the GUI thread:
void UpdateWindow(string text)
{
//safe call
Dispatcher.Invoke(() =>
{
txt.Text += text;
});
}
However, If a task is started as a result of a property changed callback from the ViewModel, there is no need to use Dispatcher.Invoke because the callback is actually executed from the UI thread.
Accessing collections on non-UI Threads
WPF enables you to access and modify data collections on threads other than the one that created the collection. This enables you to use a background thread to receive data from an external source, such as a database, and display the data on the UI thread. By using another thread to modify the collection, your user interface remains responsive to user interaction.
Value changes fired by INotifyPropertyChanged are automatically marshalled back onto the dispatcher.
How to enable cross-thread access
Remember, async method itself runs on the main thread. So this is valid:
private async void MyButton_ClickAsync(object sender, RoutedEventArgs e)
{
txt.Text = "starting"; // UI Thread
await Task.Run(()=> ExecuteLongProcedure1());
txt.Text = "waiting"; // UI Thread
await Task.Run(()=> ExecuteLongProcedure2());
txt.Text = "finished"; // UI Thread
}
Another way to invoke UI operations from UI thread is to use SynchronizationContext as described here. SynchronizationContext is a stronger abstraction than Dispatcher and it's cross-platform.
var uiContext = SynchronizationContext.Current;
while (stillWorking)
{
uiContext.Post(o =>
{
textBox.Text += ".";
}, null);
await Task.Delay(51);
}
Patterns:
Fire and forget pattern:
For obvious reasons this is how your WPF GUI event handlers such as Button_ClickAsync are called.
void Do()
{
// CPU-Bound or IO-Bound operations
}
async void DoAsync() // returns void
{
await Task.Run(Do);
}
void FireAndForget() // not blocks, not waits
{
DoAsync();
}
Fire and observe:
Task-returning methods are better since unhandled exceptions trigger the TaskScheduler.UnobservedTaskException.
void Do()
{
// CPU-Bound or IO-Bound operations
}
async Task DoAsync() // returns Task
{
await Task.Run(Do);
}
void FireAndWait() // not blocks, not waits
{
Task.Run(DoAsync);
}
Fire and wait synchronously while wasting thread resources:
This is known as Sync over async, it is a synchronous operation but it uses more than one thread which may cause starvation. This happens when you call Wait() or try to read results directly from task.Result before the task is finished.
(AVOID THIS PATTERN)
void Do()
{
// CPU-Bound or IO-Bound operations
}
async Task DoAsync() // returns Task
{
await Task.Run(Do);
}
void FireAndWait() // blocks, waits and uses 2 more threads. Yikes!
{
var task = Task.Run(DoAsync);
task.Wait();
}
Is that all to it?
No. There is a lot more to learn about async, its context and its continuation. This blogpost is especially recommended.
Task uses Thread? Are you sure?
Not necessarily. Read this answer to know more about the true face of async.
Stephen Cleary has explained async-await perfectly. He also explains in his other blog post when there is no thread involved.
Read more
ValueTask and Task
MSDN explains Task
MSDN explains async
how-to-call-asynchronous-method-from-synchronous-method
async await - Behind the scenes
async await - FAQ
Make sure you know the difference between Asynchronous, Parallel and Concurrent.
You may also read a simple asynchronous file writer to know where you should concurrent.
Investigate concurrent namespace
Ultimately, read this e-book: Patterns_of_Parallel_Programming_CSharp
Your use of TaskCompletionSource<T> is incorrect. TaskCompletionSource<T> is a way to create TAP-compatible wrappers for asynchronous operations. In your ExecuteLongProcedureAsync method, the sample code is all CPU-bound (i.e., inherently synchronous, not asynchronous).
So, it's much more natural to write ExecuteLongProcedure as a synchronous method. It's also a good idea to use standard types for standard behaviors, in particular using IProgress<T> for progress updates and CancellationToken for cancellation:
internal void ExecuteLongProcedure(int param1, int param2, int param3,
CancellationToken cancellationToken, IProgress<string> progress)
{
//Start doing work
if (progress != null)
progress.Report("Work Started");
while (true)
{
//Mid procedure progress report
if (progress != null)
progress.Report("Bath water n% thrown out");
cancellationToken.ThrowIfCancellationRequested();
}
//Exit message
if (progress != null)
progress.Report("Done and Done");
}
Now you have a more reusable type (no GUI dependencies) that uses the appropriate conventions. It can be used as such:
public partial class MainWindow : Window
{
readonly otherClass _burnBabyBurn = new OtherClass();
CancellationTokenSource _stopWorkingCts = new CancellationTokenSource();
//A button method to start the long running method
private async void Button_Click_3(object sender, RoutedEventArgs e)
{
var progress = new Progress<string>(data => UpdateWindow(data));
try
{
await Task.Run(() => _burnBabyBurn.ExecuteLongProcedure(intParam1, intParam2, intParam3,
_stopWorkingCts.Token, progress));
}
catch (OperationCanceledException)
{
// TODO: update the GUI to indicate the method was canceled.
}
}
//A button Method to interrupt and stop the long running method
private void StopButton_Click(object sender, RoutedEventArgs e)
{
_stopWorkingCts.Cancel();
}
//A method to allow the worker method to call back and update the gui
void UpdateWindow(string message)
{
TextBox1.Text = message;
}
}
Here is an example using async/await, IProgress<T> and CancellationTokenSource. These are the modern C# and .Net Framework language features that you should be using. The other solutions are making my eyes bleed a bit.
Code Features
Count to 100 over a period of 10 seconds
Display progress on a progress bar
Long running work (a 'wait' period) performed without blocking the UI
User triggered cancellation
Incremental progress updates
Post operation status report
The view
<Window x:Class="ProgressExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" SizeToContent="WidthAndHeight" Height="93.258" Width="316.945">
<StackPanel>
<Button x:Name="Button_Start" Click="Button_Click">Start</Button>
<ProgressBar x:Name="ProgressBar_Progress" Height="20" Maximum="100"/>
<Button x:Name="Button_Cancel" IsEnabled="False" Click="Button_Cancel_Click">Cancel</Button>
</StackPanel>
</Window>
The code
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private CancellationTokenSource currentCancellationSource;
public MainWindow()
{
InitializeComponent();
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
// Enable/disabled buttons so that only one counting task runs at a time.
this.Button_Start.IsEnabled = false;
this.Button_Cancel.IsEnabled = true;
try
{
// Set up the progress event handler - this instance automatically invokes to the UI for UI updates
// this.ProgressBar_Progress is the progress bar control
IProgress<int> progress = new Progress<int>(count => this.ProgressBar_Progress.Value = count);
currentCancellationSource = new CancellationTokenSource();
await CountToOneHundredAsync(progress, this.currentCancellationSource.Token);
// Operation was successful. Let the user know!
MessageBox.Show("Done counting!");
}
catch (OperationCanceledException)
{
// Operation was cancelled. Let the user know!
MessageBox.Show("Operation cancelled.");
}
finally
{
// Reset controls in a finally block so that they ALWAYS go
// back to the correct state once the counting ends,
// regardless of any exceptions
this.Button_Start.IsEnabled = true;
this.Button_Cancel.IsEnabled = false;
this.ProgressBar_Progress.Value = 0;
// Dispose of the cancellation source as it is no longer needed
this.currentCancellationSource.Dispose();
this.currentCancellationSource = null;
}
}
private async Task CountToOneHundredAsync(IProgress<int> progress, CancellationToken cancellationToken)
{
for (int i = 1; i <= 100; i++)
{
// This is where the 'work' is performed.
// Feel free to swap out Task.Delay for your own Task-returning code!
// You can even await many tasks here
// ConfigureAwait(false) tells the task that we dont need to come back to the UI after awaiting
// This is a good read on the subject - https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
await Task.Delay(100, cancellationToken).ConfigureAwait(false);
// If cancelled, an exception will be thrown by the call the task.Delay
// and will bubble up to the calling method because we used await!
// Report progress with the current number
progress.Report(i);
}
}
private void Button_Cancel_Click(object sender, RoutedEventArgs e)
{
// Cancel the cancellation token
this.currentCancellationSource.Cancel();
}
}
This is a simplified version of the most popular answer here by Bijan. I simplified Bijan's answer to help me think through the problem using the nice formatting provided by Stack Overflow.
By carefully reading and editing Bijan's post I finally understood: How to wait for async method to complete?
In my case the chosen answer for that other post is what ultimately led me to solve my problem:
"Avoid async void. Have your methods return Task instead of void. Then you can await them."
My simplified version of Bijan's (excellent) answer follows:
1) This starts a task using async and await:
private async void Button_Click_3(object sender, RoutedEventArgs e)
{
// if ExecuteLongProcedureAsync has a return value
var returnValue = await Task.Run(()=>
ExecuteLongProcedureAsync(this, intParam1, intParam2, intParam3));
}
2) This is the method to execute asynchronously:
bool stillWorking = true;
internal void ExecuteLongProcedureAsync(MainWindow gui, int param1, int param2, int param3)
{
//Start doing work
gui.UpdateWindow("Work Started");
while (stillWorking)
{
//put a dot in the window showing the progress
gui.UpdateWindow(".");
//the following line blocks main thread unless
//ExecuteLongProcedureAsync is called with await keyword
System.Threading.Thread.Sleep(50);
}
gui.UpdateWindow("Done and Done");
}
3) Invoke the operation which involves a property from gui:
void UpdateWindow(string text)
{
//safe call
Dispatcher.Invoke(() =>
{
txt.Text += text;
});
}
Or,
void UpdateWindow(string text)
{
//simply
txt.Text += text;
}
Closing comments) In most cases you have two methods.
First method (Button_Click_3) calls the second method and has the async modifier which tells the compiler to enable threading for that method.
Thread.Sleep in an async method blocks the main thread. but awaiting a task does not.
Execution stops on current thread (second thread) on await statements until task is finished.
You can't use await outside an async method
Second method (ExecuteLongProcedureAsync) is wrapped within a task and returns a generic Task<original return type> object which can be instructed to be processed asynchronously by adding await before it.
Everything in this method in executed asynchronously
Important:
Liero brought up an important issue. When you are Binding an element to a ViewModel property, the property changed callback is executed in UI thread. So there is no need to use Dispatcher.Invoke. Value changes fired by INotifyPropertyChanged are automatically marshalled back onto the dispatcher.

Categories

Resources