This question already has answers here:
An async/await example that causes a deadlock
(5 answers)
Closed 4 years ago.
I know there are quite a lot of Post about Task deadlocks, but I simply can't find the right sollution.
So I basically have this setup:
public event EventHandler StateChangedEvent;
public bool Busy
{
...
set
{
...
this.StateChangedEvent?.Invoke(this, EventArgs.Empty)
}
}
public void Main()
{
...
this.StateChangedEvent += this.OnStateChangedEvent;
}
public void OnStateChangedEvent(object sender, EventArgs e)
{
this.TextBox.Invoke(() => this.TextBox.Text = "Change");
this.Invoke(() => this.Cursor = Cursors.WaitCursor);
}
public void ButtonAction_Click(object sender, EventArgs e) //actually part of an API with an virtal - override method on between. Can't change here to async
{
...
Task.Run(async () => await this.AsyncDoStuff()).Wait();
... // Synchron stuff needs to be done afterwards
}
public async Task AsyncDoStuff()
{
this.Busy = true; //Causes Deadlock
await Stuff1();
await Stuff2();
}
So in reality those calls are split among different classes, but the basic structure remains. Yes I know I should go async all the way up, but let's say the first ButtonAction_Click is part op an API/Framework and can't be changed to async.
I know the reason is because I block the UI Thread and then access it again...So what is the best solution for this?
Thanks in advance!
So from your other comments it sounds like the code in ButtonAction_Click is outside your control and you can't change it. Unfortunately, that's where the problem is - this event handler is totally blocking the UI thread until the work has finished. There's no way to unblock the thread.
Your only recourse is to avoid any blocking interactions with the UI thread.
The following code from your example is definitely going to cause deadlock, because Invoke() will block until the UI (which is already blocked) responds:
this.TextBox.Invoke(() => this.TextBox.Text = "Change");
this.Invoke(() => this.Cursor = Cursors.WaitCursor);
You could try using BeginInvoke() instead of Invoke(), but the unfortunate consequence is that these UI changes won't actually execute until the UI thread is unblocked, and by then your background work is already finished. It might fix your deadlock, though.
Related
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.
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
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.
I've asked a question on how to know when a string of another other party library code changes in my code. I can get access to the string itself at any time. but can't implement INotifyPropertyChanged since it's not my code.
I was offered to use a BackgroundWorker and this solution does work for me!
but, I was trying to make sure it is the best solution and got an advise to look at TPL, further researching showed that Task.Run of TPL might be a better solution, as mentioned here for example: Task parallel library replacement for BackgroundWorker? but I couldn't implement it in code.
I am trying to replace this code by Task.Run (Thanks to #a.azemia)
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += (s, e) =>
{
while (true)
{
if (!fc.SecondString.Equals(AnotherPartyLibrary.firstString))
{
fc.SecondString = AnotherPartyLibrary.firstString;
}
Thread.Sleep(1000);
}
};
bw.RunWorkerAsync();
I couldn't find any example that fit my scenario and tried to learn from other examples with no success. I need a while loop inside the task and it needs to run asynchronously like the BackgroundWorker does.
couldn't find any example with a while loop in the task, so I am not sure of how this can be done.
I've also read that Lambda expressions uses more resources and it was shown in some test that I've seen so I would've liked to avoid Lambda if possible.
Thanks for the help!
Try this (untested):
public async Task DoWork()
{
while (true)
{
if (!fc.SecondString.Equals(AnotherPartyLibrary.firstString))
{
fc.SecondString = AnotherPartyLibrary.firstString;
}
await Task.Delay(1000);
}
}
I've used Task.Delay instead of Thread.Sleep as the former does not block a thread while delay is happening. You can invoke this function with await
await DoWork();
I still see no real benefit, but here you go:
private Task T;
private void Form1_Load(object sender, EventArgs e)
{
// ... make sure your string stuff is setup first ...
T = Task.Run(delegate() {
while (true)
{
// ... code ...
System.Threading.Thread.Sleep(1000);
}
});
}
This question already has answers here:
The calling thread cannot access this object because a different thread owns it
(15 answers)
Closed 2 years ago.
Is there a way to solve this error " The calling thread cannot access this object because a different thread owns it" without using dispatcher because dispatcher causes freezing on UI when the codes has a longer time to process is there another way to do it? without causing the freeze on the UI
No, you have to update the UIElement on the UI thread as the error says.
Yes, there other ways to run something on the UI thread other than using the Dispatcher, but they like the Dispatcher still run whatever it is you want to run on the UI thread - so will still freeze the UI.
If you are using C# 5 and .NET 4.5 or above you can easily run your long running process without blocking the UI Thread then when it completes continue on the UI thread (without worrying about how it works) using the async and await keywords:
private async Task<string> SimLongRunningProcessAsync()
{
await Task.Delay(2000);
return "Success";
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
button.Content = "Running...";
var result = await SimLongRunningProcessAsync();
button.Content = result;
}
If you do not have those however you will want to use the Dispatcher. The Dispatcher actually assists you running processes without freezing the UI
What you want to do is run the long running processes off the UI thread then when it is finished update the UI - which the Dispatcher helps you to:
Start long process on another thread and return immediately.
(long process still running, UI continues to update)
Long process finishes, update the UI on the UI thread.
e.g.:
private void UpdateButtonContent(string text)
{
button.Content = text;
}
private void SimLongRunningProcess()
{
Thread.Sleep(2000);
}
private void OnProcessFinished(Task task)
{
string content;
if(task.Exception != null)
{
content = task.Exception.Message;
}
else
{
content = "Success";
}
Dispatcher.BeginInvoke(new Action<string>(UpdateButtonContent), DispatcherPriority.Normal, content);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// Start long running process and return immediatly
var task = Task.Factory.StartNew(SimLongRunningProcess);
task.ContinueWith(OnProcessFinished);
}
If you are using .NET 4.0 or newer, you can utilize the async and await keywords for clean, asynchronous code. This feature is built into 4.5 directly, and for 4.0 there is a NuGet package available from Microsoft (Microsoft.Bcl.Async) to enable this functionality.
For example, a user clicks a button and you wish to do something that may take a bit of time, then report back to the user.
// Notice how this method is marked 'async', this allows the 'await' keyword
async void OnButtonClicked(object sender, EventArgs e)
{
var button = sender as Button;
button.IsEnabled = false;
button.Text = "Calculating...";
int result = await DoSomeWork();
button.IsEnabled = true;
button.Text = "Calculate";
}
// This is an asynchronous method that returns an integer result
Task<int> DoSomeWork()
{
// Do some lengthy computation here, will be run on a background thread
return 42;
}
Alternatively, you could use other mechanisms like the BackgroundWorker class, or the Asynchronous Programming Model (APM) with callbacks. These are fine, however the async/await pattern is preferable.
If you have a choice, target .NET 4.5 (Win7+). If you must also support Windows XP, target .NET 4.0 and use the NuGet packages for Microsoft.Bcl.Async.