RaiseCanExecuteChanged called while await causes deadlock - c#

I am using WPF and DelegateCommand from PRISM and have the following problem:
I start an async operation like:
public async void ProgramDevice()
{
var result = await FirmwareLoader.DownloadFirmwareAsync();
}
Inside this method an event is fired which I registered to and should update my DelegateCommand so it can't be executed:
//UiCommand is of type DelegateCommand
Engine.IsProgrammedChanged +=
(s, e) => Dispatcher.Invoke(() => UiCommand.RaiseCanExecuteChanged());
Now I have the problem, that the RaiseCanExecuteChanged causes a deadlock (I checked and the Dispatcher.Invoke does not cause it, because when I e.g. show a MessageBox instead it works fine).
Am I doing something wrong or how can I work around this problem?

I see you've already solved your problem, but I thought I'd give a more general solution that will help you prevent such deadlocks in the future.
In your case, you could easily avoid this deadlock by using ConfigureAwait like this:
var result = await FirmwareLoader.DownloadFirmwareAsync().ConfigureAwait(false);
What this does is allows the continuation to be performed on a different thread than the original. Doing so is not always possible, since a lot of times you need the continuation to be performed on the UI thread, but for this question I don't believe that's the case. So basically, the best practice is to always use ConfigureAwait(false) unless you need to resume execution from the original thread.
This article explains in detail why these kind of deadlocks happen and how to avoid them. Another recommended read is Best Practices in Asynchronous Programming.

Found the problem:
It was not the RaiseCanExecuteChanged, but the actual CanExecute which is triggered by it. In there I had an AsyncLock which waited for the programming task to be finished, before returning the value I use to descide if UiCommand can be executed --> deadlock as the programming task triggered it...
I solved it by simple using the "sync" property (which does not use the lock and just returns the current value/stat) of the value I need.

Am I doing something wrong or how can I work around this problem?
Method Dispatcher.Invoke blocks working thread until UI thread makes all updates
UI thread uses some resources locked by working thread (through RaiseCanExecuteChanged -> CanExecute method chain in the above code) and blocks
Deadlock since worker thread waits for UI thread to finish update and UI thread waits worker thread to release locked resources
A possible way to ensure no deadlocks is to asynchronously invoke updates on UI thread using Dispatcher.BeginInvoke.
//UiCommand is of type DelegateCommand
Engine.IsProgrammedChanged +=
(s, e) => Dispatcher.BeginInvoke(() => UiCommand.RaiseCanExecuteChanged());
This way UI thread will wait for a moment when working thread releases locked resources and then will update. But there will be no deadlock.

Related

Changing some Dispatcher.BeginInvoke functionality into that of Dispatcher.Invoke

The reason for what I'm going to ask here is that Dispatcher.Invoke throws a TaskCanceledException when another thread executes Dispatcher.InvokeShutdown(). Dispatcher.BeginInvoke() does not seem to suffer from this and I wanted to move my codebase from using Dispatcher.Invoke(...) to Dispatcher.BeginInvoke(...). And below I wanted to ask if the following two Work() methods both running on a separate background thread are equivalent? (do any of you see any issues changing the first into the second?):
Work(){
Dispatcher.Invoke(() => {sameFunction()});
//more work
...
}
Work(){
var task = Dispatcher.BeginInvoke((Action)(() => {sameFunction()});
task.Wait();
//more work
...
}
This issue is a direct consequence of the following issue's answer not having functioned as hoped for. It seems that once Dispatcher.InvokeShutdown has been called (once Dispatcher.HasShutdownStarted is true), all calls to Dispatcher.Invoke will end in throwing a TaskCancelledException.
You should use Dispatcher.InvokeAsync instead of Dispatcher.BeginInvoke. BeginInvoke is part of the old API.
Also, never call Wait(), but use await:
await Dispatcher.InvokeAsync()
Using the new API also allows you to cancel operations (Invoke and InvokeAsync only): to fix the exception issue, you should provide a shared CancellationToken, that you associate with the Dispatcher (virtually, with the one you expect to get shutdown), to every invocation.
This way you can cancel the pending and running operations gracefully before you shutdown the Dispatcher.
Dispatcher.InvokeShutdown will abort any running Dispatcher operation, which applies to every synchronous Dispatcher.Invoke execution - hence the TaskCanceledException is being thrown on abortion.
Regarding Dispatcher.InvokeAsync (and Dispatcher.BeginInvoke): your probably don't experience the cancellation exception, because the dispatched operation is still pending due to its asynchronous execution.
This leads to the difference of both Dispatcher invocation examples:
Your first example uses Dispatcher.Invoke. From the documentation you could learn that it executes synchronously. This means, the delegate is executed immediately (pushed to the front of the queue - respecting the assigned priorities).
The second example uses Dispatcher.BegingInvoke (same applies to the modern Dispatcher.InvokeAsync). This method invokes the delegate asynchronously. This means, the delegate is enqueued into the dispatcher queue and executed after all preceeding pending operations in this queue are completed. If you don't await the call, the Dispatcher returns immediately after enqueuing the delegate and execution continues (this is the asynchronous part).
Therfore, the examples are not equivalent. You have to decide if postponing the delegate's execution is reasonable (Dispatcher.InvokeAsync) or not (Dispatcher.Invoke).

AutoResetEvent.WaitOne() cause deadlock

I'm writing a application with a critical region.
And I decide to use AutoResetEvent to achieve mutual exclusion.
Here's the code
public class MyViewModel
{
private AutoResetEvent lock = new AutoResetEvent(true);
private aync Task CriticalRegion()
{
Dosomething();
}
public async Task Button_Click()
{
Debug.WriteLine("Entering Button_Click");
lock.WaitOne();
try
{
await CriticalRegion();
}
finally
{
lock.Set();
Debug.WriteLine("Leaving Button_Click");
}
}
}
I have a button whose click event calls the Button_Click() method
It works normally. But, if I'm quick enough to click the button for another time before the first call to Button_Click() completes, the whole app stops responding.
In the Debug window I find something like this
Entering Button_Click
Entering Button_Click
Looks like the method never completes.
I struggled a bit and find that if I change lock.WaitOne(); to
if (!sync.WaitOne(TimeSpan.FromSeconds(1)))
{
return;
}
In this case my app is able to avoid the deadlock,but I don't know why it works.
I only know about the IPC from my OS course and the async and await pattern in C#, and I'm not so familiar with the thread in .Net world.
I really want to understand what's really going on behind the scenes.
Thanks for any replys ;)
You have a deadlock because WaitOne is blocking the main thread (button click handler is executed on the main thread), while you haven't called ConfigureAwait(false) when calling await, which means that it tries to run the code which is after await on the main thread, even if it's blocked, which would causes a deadlock.
I suggest reading this post for a thorougher explanation of the dead lock situation.
For your code, I would suggest putting the lock deeper, probably within the async Task, and trying to use a more suitable pattern for locking, preferably, the lock statement, because using Event objects is awkward for mutual exclusion, as Hans stated in the comment.
AutoResetEvent.WaitOne() will block infinitely until you call AutoResetEvent.Set(), which you never seem to do except for after the WaitOne() call.
Quoting the AutoResetEvent.WaitOne() documentation:
Blocks the current thread until the current WaitHandle receives a signal.

C# Thread.Sleep()

I need somehow to bypass Thread.Sleep() method and don't get my UI Thread blocked, but I don't have to delete the method.
I need to solve the problem without deleting the Sleep method. The Sleep method simulates a delay(unresponsive application). I need to handle that.
An application is considered non-responsive when it doesn't pump its message queue. The message queue in Winforms is pumped on the GUI thread. Therefore, to make your application "responsive", you need to make sure the GUI thread has opportunities to pump the message queue - in other words, it must not run your code.
You mentioned that the Thread.Sleep simulates a "delay" in some operation you're making. However, you need to consider two main causes of such "delays":
An I/O request waiting for completion (reading a file, querying a database, sending an HTTP request...)
CPU work
The two have different solutions. If you're dealing with I/O, the best way would usually be to switch over to using asynchronous I/O. This is a breeze with await:
var response = await new HttpClient().GetAsync("http://www.google.com/");
This ensures that your GUI thread can do its job while your request is pending, and your code will restore back on the UI thread after the response gets back.
The second one is mainly solved with multi-threading. You should be extra careful when using multi-threading, because it adds in many complexities you don't get in a single-threaded model. The simplest way of treating multi-threading properly is by ensuring that you're not accessing any shared state - that's where synchronization becomes necessary. Again, with await, this is a breeze:
var someData = "Very important data";
var result = await Task.Run(() => RunComplexComputation(someData));
Again, the computation will run outside of your UI thread, but as soon as its completed and the GUI thread is idle again, your code execution will resume back on the UI thread, with the proper result.
something like that maybe ?
public async void Sleep(int milliseconds)
{
// your code
await Task.Delay(milliseconds); // non-blocking sleep
// your code
}
And if, for reasons that escape me, you HAVE to use Thread.Sleep, you can handle it like that :
public async void YourMethod()
{
// your code
await Task.Run(() => Thread.Sleep(1000)); // non-blocking sleep using Thread.Sleep
// your code
}
Use MultiThreading.
Use a different thread for sleep rather than the main GUI thread. This way it will not interfere with your Main application

Raising PropertyChanged in asynchronous Task and UI Thread

At many blogs, tutorials and MSDN I can read that accessing UI elements from non-UI threads is impossible - ok, I'll get an unauthorized exception. To test it I've written a very simple example:
// simple text to which TextBlock.Text is bound
private string sample = "Starting text";
public string Sample
{
get { return sample; }
set { sample = value; RaiseProperty("Sample"); }
}
private async void firstButton_Click(object sender, RoutedEventArgs e)
{
await Job(); // asynchronous heavy job
commands.Add("Element"); // back on UI thread so this should be ok?
}
private async Task Job()
{
// I'm not on UI Thread ?
await Task.Delay(2000); // some other job
Sample = "Changed"; // not ok as not UI thread?
commands.Add("Element from async"); // also not ok?
}
I've a Task which is being run asynchronously. In that Task I want to change my property (which will raise PropertyChanged) and add element to ObservableCollection. As it is run async, I shouldn't be able to do that, but I get no exception and the code is working fine. Thus my doubts and misunderstanding:
why don't I get an exception?
is it ok to raise PropertyChanged in async Task?
is it ok to modify ObservableCollection in async Task, or should I return Task<ICollection> and after obtaining the result modify the ObservableCollection- Clear it and Fill it?
when am I in Task on UI thread and when not?
in the code above in firstButton_Click is it ok to manage UI elements after awaiting the Task? Am I always back on UI thread?
To test it more I've put my property change and collection modification in other thread:
System.Threading.Timer newThreadTimer = new System.Threading.Timer((x) =>
{
Sample = "Changed"; // not UI thread - exception
commands.Add("Element from async"); // not UI thread - exception
}, null, 1000, Timeout.Infinite);
In above code my thinking is ok - just after the first or second line I get an exception. But what with the first code? Is it only a luck that my Taskwas run on UI thread?
I suspect that this is very basic thing and my misunderstanding, but I need some clarification and thus this question.
When awaiting on a Task, the SynchronizationContext of the current thread is captured (specifically in the case of Task by the TaskAwaiter). The continutation is then marshaled back to that SynchronizationContext to execute the rest of the method (the part after the await keyword).
Lets look at your code example:
private async Task Job()
{
// I'm not on UI Thread ?
await Task.Delay(2000); // some other job
Sample = "Changed"; // not ok as not UI thread?
commands.Add("Element from async"); // also not ok?
}
When you await Task.Delay(2000), the compiler implicitly captures the SynchronizationContext, which is currently your WindowsFormsSynchronizationContext. When the await returns, the continuation is executed in the same context, since you didn't explicitly tell it not to, which is your UI thread.
If you changed your code to await Task.Delay(200).ConfigureAwait(false), the continuation would not be marshalled back to your current SynchronizationContext, and would run a ThreadPool thread, causing your UI element update to throw an exception.
In your timer example, the Elapsed event is raised via a ThreadPool thread, hence why you get an exception that you are trying to update an element which is controlled by a different thread.
Now, let's go over your questions one by one:
why don't I get exception?
As said, the await Task.Delay(2000) executed the Continuation on the UI thread, which made it possible to update your controls.
is it ok to Raise properties in async Task?
I am not sure what you mean by "Raise properties", but if you mean raise a INotifyPropertyChanged event, then yes, it is ok to execute them not in a UI thread context.
is it ok to modify ObservableCollecition in async Task, or should I
return Task and after obtaining the result modify Observable - Clear
it and Fill it?
If you have an async method and you want to update a UI bound element, make sure you marshal the continuation on the UI thread. If the method is called from the UI thread and you await its result, then the continuation will implicitly be ran on your UI thread. In case you want to offload work to a background thread via Task.Run and make sure your continuation is ran on the UI, you can capture your SynchronizationContext using TaskScheduler.FromCurrentSynchronizationContext() and explicitly pass it the continuation
when am I in Task on UI thread and when not?
A Task is a promise of work that will be done in the future. when you await on a TaskAwaitable from the UI thread context, then you are still running on the UI thread. You are not in the UI thread if:
Your async method is currently executing from a thread different then the UI thread (either a ThreadPool thread or a new Thread)
You offload work to a background ThreadPool thread using Task.Run.
in the code above in firstButton_Click is it ok to manage UI elements
after awaiting the Task? Am I always back on UI thread?
You will be back to the UI thread as long as you don't explicitly tell your code not to return to its current context using ConfigureAwait(false)
The PropertyChanged event is automatically dispatched to the UI thread by WPF so you can modify properties that raise it from any thread. Before .NET 4.5 this was not the case for ObservableCollection.CollectionChanged event and thus, adding or removing elements from a thread other than the UI one, would cause an exception.
Starting in .NET 4.5 CollectionChanged is also automatically dispatched to the UI thread so you don't need to worry about that. This being said, you'll still need to access UI elements (such as a button for instance) from the UI thread.

AsyncAwait causes unexpected method behavior, Methods runs in wrong thread if called from constructor

I'm trying to do some time consuming actions without freezing the GUI Thread. The UpdateSomething Method is called in two places once in the constructor of my ViewModel and once on button click (RelayCommand). The Method is executed in a WorkerThread if the method is called via RelayCommand, but runs in the MainThread (GUI) when the method call comes from the constructor.
What causes this strange behavior? I double check a few times via IntelliTrace.
This is the method in question:
private async void UpdateSomething()
{
var item = await Task.Factory.StartNew(() =>this.DoSomething("I should run async"));
this.TestItem = item;
}
I'm using WPF and .Net 4.5
For the case where the Tasks action runs on the main thread, the most likely cause is that the method UpdateSomething is being called from within another Task (a Task that was scheduled to run on the main thread). In that case, the TaskScheduler.Current is the main thread TaskScheduler not the TaskScheduler.Default which queues work to the thread pool.
Task.Factory.StartNew defaults to using TaskScheduler.Current (you can change what it uses by calling the appropriate override), while Task.Run uses TaskScheduler.Default.
The statement that Task.Factory.StartNew doesn't play will with async/await is not correct, it's just that some of the defaults are probably not what you want for the common case (this is part of whyTask.Run was introduced).
See:
http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx
Why is TaskScheduler.Current the default TaskScheduler?
I ran into the same problem a while ago. I stuck up a little post about it here:
Today I had a major hair pulling moment. I was using a await/async on a block of code wrapped in a new task. No matter what I did it would just start the Task but then not wait for the result.
After much frustration I worked out that using await Task.Factory.StartNew doesn't play well with await.
In the end I simply changed it to Task.Run what was then worked fine.
Basically you need to use Task.Run instead because await doesn't play nicely with Task.Factory.StartNew
This question was answered by #Rene147 but he deleted his answer. (for whatever reason)
I will briefly rephrase what he had written:
await/asycn doesn't play very well with Task.Factory.StartNew().
Simply replace Task.Factory.StartNew by Task.Run and everything should work:
private async void UpdateSomething()
{
//not working when call comes from constructor
//var item = await Task.Factory.StartNew(() =>this.DoSomething("I should run async"));
//working
var item = await Task.Run(() =>this.DoSomething("I run async!"));
this.TestItem = item;
}
Rene147 also wrote a short blogpost about it.
Would be happy to get more information about this issue, still seems odd to me.

Categories

Resources