Question

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?

Was it helpful?

Solution 2

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.

OTHER TIPS

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.

Am I doing something wrong or how can I work around this problem?

  1. Method Dispatcher.Invoke blocks working thread until UI thread makes all updates

  2. UI thread uses some resources locked by working thread (through RaiseCanExecuteChanged -> CanExecute method chain in the above code) and blocks

  3. 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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top