これを刺してみます...
CodePlex サイトで MVVM-Light ソース コードを確認できます。関連するメソッドをここに貼り付けます (この投稿のために少し注釈を付けています)。
private void SendToTargetOrType<TMessage>(TMessage message, Type messageTargetType, object token)
{
var messageType = typeof(TMessage);
if (_recipientsOfSubclassesAction != null)
{
// Clone to protect from people registering in a "receive message" method
// Correction Messaging BL0008.002
var listClone =
_recipientsOfSubclassesAction.Keys.Take(_recipientsOfSubclassesAction.Count()).ToList();
foreach (var type in listClone)
{
List<WeakActionAndToken> list = null;
if (messageType == type
|| messageType.IsSubclassOf(type)
|| type.IsAssignableFrom(messageType))
{
lock (_recipientsOfSubclassesAction)
{
list = _recipientsOfSubclassesAction[type].Take(_recipientsOfSubclassesAction[type].Count()).ToList();
}
}
// Class A probably sends a message here from the UI thread
SendToList(message, list, messageTargetType, token);
}
}
if (_recipientsStrictAction != null)
{
// Class B grabs this lock on the background thread.
// Class A continues processing on the UI thread and arrives here.
// An attempt is made to grab the lock on the UI thread but it is
// blocked by the background thread & Class B which in turn is waiting
// on the UI thread. And here you have yourself a deadlock
lock (_recipientsStrictAction)
{
if (_recipientsStrictAction.ContainsKey(messageType))
{
var list = _recipientsStrictAction[messageType]
.Take(_recipientsStrictAction[messageType].Count())
.ToList();
// Class B sends its message here.
// Class C receives the message and does an Invoke on the UI thread
SendToList(message, list, messageTargetType, token);
}
}
}
RequestCleanup();
}
- クラス A は、おそらく「サブクラスの受信者」によってピックアップされた UI スレッドでメッセージを送信します。
- クラス B は、このメッセージを受け取り、バックグラウンド タスクを開始する受信者です。
- バックグラウンド タスクは、「厳密なアクションの受信者」を持つメッセージを送信します。
- クラス B は、バックグラウンド スレッドで '_recipientsStrictAction' ロックを取得します。
- クラス B はメッセージをクラス C に送信し、クラス C は UI スレッドで呼び出しを行います。
- UI スレッドがまだ最初のメッセージを実行しているため、この呼び出しはブロックされます。
- UI スレッドの実行は続行され、UI スレッドの '_recipientsStrictAction' ロックを取得しようとします。残念ながら、(UI スレッドで待機している) バックグラウンド スレッドは既にロックされています。あなたは今行き詰まっています:(
Invoke ではなく、クラス C で InvokeAsync を実行することを検討してください。そうすれば、おそらく問題を回避できると思います。
MVVMライトがロックの「内側」にメッセージを送信する理由を不思議に思います。あまりクールではない種類のことのようです。これをすべて入力した後、CodePlex サイトを見回しました。これは問題が文書化されているようです:
http://mvvmlight.codeplex.com/workitem/7581