2

私は WPF とDelegateCommandPRISM を使用しており、次の問題があります。

次のような非同期操作を開始します。

public async void ProgramDevice()
{
    var result = await FirmwareLoader.DownloadFirmwareAsync();
}

このメソッド内で、登録したイベントが発生し、DelegateCommand実行できないように更新する必要があります。

//UiCommand is of type DelegateCommand
Engine.IsProgrammedChanged += 
    (s, e) => Dispatcher.Invoke(() => UiCommand.RaiseCanExecuteChanged());

RaiseCanExecuteChanged、デッドロックが発生するという問題があります(Dispatcher.Invokeたとえば、代わりに MessageBox を表示すると正常に動作するため、確認しましたが、原因ではありません)。

何か間違ったことをしていますか、またはこの問題を回避するにはどうすればよいですか?

4

3 に答える 3

1

すでに問題を解決されているようですが、将来このようなデッドロックを防ぐのに役立つ、より一般的な解決策を提供したいと思いました.

あなたの場合、次のように使用することで、このデッドロックを簡単に回避できますConfigureAwait

var result = await FirmwareLoader.DownloadFirmwareAsync().ConfigureAwait(false);

これにより、元のスレッドとは異なるスレッドで継続を実行できるようになります。多くの場合、UI スレッドで継続を実行する必要があるため、これが常に可能であるとは限りませんが、この質問については、そうではないと思います。ConfigureAwait(false)したがって、基本的には、元のスレッドから実行を再開する必要がない限り、常に使用することをお勧めします。

この記事では、この種のデッドロックが発生する理由と回避方法について詳しく説明します。別の推奨される読み物は、Best Practices in Asynchronous Programmingです。

于 2013-09-06T23:11:52.357 に答える
0

問題が見つかりました:
それは ではなく、それによって引き起こされるRaiseCanExecuteChanged実際のものでした。CanExecuteそこにはAsyncLock、プログラミングタスクが終了するのを待ってから、実行できるかどうかを判断するために使用する値を返す前にUiCommand->プログラミングタスクがトリガーしたときにデッドロックが発生しました...

必要な値の「同期」プロパティ(ロックを使用せず、現在の値/統計を返すだけ)を使用して簡単に解決しました。

于 2013-09-06T11:24:45.177 に答える
0

何か間違ったことをしていますか、またはこの問題を回避するにはどうすればよいですか?

  1. Dispatcher.InvokeUI スレッドがすべての更新を行うまで、メソッドは作業スレッドをブロックします

  2. UI スレッドは、作業スレッドによってロックされたいくつかのリソースを使用し (上記のコードのRaiseCanExecuteChanged->CanExecuteメソッド チェーンを介して)、ブロックします。

  3. ワーカー スレッドが UI スレッドが更新を完了するのを待機し、UI スレッドがワーカー スレッドがロックされたリソースを解放するのを待機するため、デッドロックが発生する

デッドロックが発生しないようにするために考えられる方法は、 を使用して UI スレッドで非同期に更新を呼び出すことDispatcher.BeginInvokeです。

//UiCommand is of type DelegateCommand
Engine.IsProgrammedChanged += 
    (s, e) => Dispatcher.BeginInvoke(() => UiCommand.RaiseCanExecuteChanged());

このように、UI スレッドは、作業中のスレッドがロックされたリソースを解放してから更新するまでしばらく待機します。しかし、デッドロックは発生しません。

于 2015-02-15T18:26:32.177 に答える