2013-03-28 53 views
2

這裏基本上是正在發生的事情....嵌套MVVM光信使而使用分派+多線程=死鎖

  1. 類A(主線程)發送一個消息MVVM
    • 此消息是發送接收,並且在處理過程中,B類構建並開始後臺任務。
    • 此背景發送單獨的MVVM消息。
    • C類已經註冊了此消息,並在調度程序上調用嘗試更新UI。
    • 此時主線程仍在執行原來的發送命令和的線程死鎖(我可以暫停調試器,看看他們都在等待)。

其他注意事項

  1. 如果我在後臺線程增加睡眠一秒鐘(允許主線程的發送方法來完成),它工作正常。
  2. 這僅當有另一個線程上它調用在調度發送的嵌套MVVM消息發生的情況。
    • 註釋掉調度電話...罰款。
    • 不使用MVVM消息來調用調度程序...很好。

任何人能解釋這是怎麼回事?

回答

2

我帶你去一個刺在這個...

你可以看看它的CodePlex網站上的MVVM光源代碼。我要去這裏的相關方法(略註解這個職位的緣故)粘貼:

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(); 
    } 
  1. A類可能是'子收件人發送UI線程上的消息拾起。
  2. B類是收到此消息並啓動後臺任務的收件人。
  3. 您的後臺任務隨後會發送一條包含「嚴格操作收件人」的郵件。
  4. B類在後臺線程上抓取'_recipientsStrictAction'鎖。
  5. B類將消息發送給C類,它在UI線程上執行一個調用。
  6. 這將調用塊,因爲UI線程仍在執行第一條消息。
  7. UI線程繼續執行,然後試圖搶在UI線程上的「_recipientsStrictAction」鎖。不幸的是,你的後臺線程(在UI線程上等待)已經有鎖。你現在處於死鎖狀態:(

可能想考慮在類C中做一個InvokeAsync而不是一個Invoke,我想你應該可以避免這個問題。

讓我想知道爲什麼MVVM燈會在鎖內發送消息。看起來像一個不太酷的事情要做。打完所有這些後,我去了解CodePlex站點,看起來像這個問題已被記錄: http://mvvmlight.codeplex.com/workitem/7581