2011-07-28 27 views
2

我有一個奇怪的死鎖情況。附加視覺工作室後。我看到3個線程卡住了。在.net中發生事件的僵局

  1. 線程1:

    if (SomeEvent != null) 
        SomeEvent(this, new SomeArg) --> Stuck 
    
  2. 線程2:

    if (SomeEvent2 != null) 
        SomeEvent2(this, new SomeArg2) --> Stuck 
    
  3. 主線:

    public object (Delegate method, object[] args) 
    { 
        ... 
        SynchronizationContext.Send(delegate(object state)) 
        { 
         ... 
         method.DynamicInvoke(args); --> Stuck 
        } 
    } 
    

這三個線程都卡住了,當我檢查它們的調用堆棧時,我無法找到任何共享資源,如lock()Monitor.Wait()。我相信他們都堅持打外線電話。

此外,我不知道什麼method.DynamicInvoke(args)正在做什麼,這種方法應該是什麼。

我發現的唯一一件事是附加的事件處理程序可能會導致死鎖。然而,由於VS已經告訴我這是它的位置,而不是事件處理程序的代碼。我認爲這可能是別的。

就應用程序而言,我知道這是一個競爭條件,因爲應用程序試圖在同一時間執行加載和卸載數據,所以這個問題很難重現。

我的問題是:

  1. 爲什麼.NET引發一個事件時危在旦夕,是它甚至可能嗎?
  2. 舉辦活動時是否需要使用主UI線程?
  3. 如果確實有可能導致事件發生僵局,我應該如何防止這種情況發生?

感謝

回答

1
  1. 是否有可能引發一個事件,當一個線程掛起?是的。在事件處理程序完成之前,執行線程不會從事件發生返回。事件處理程序可以是任何東西,因此它們可以掛起。如果事件處理程序掛起,則事件引發線程將掛起。

  2. 不,主UI線程不需要用於引發事件。任何線程都可以引發事件。

  3. 事件引發不是特別容易發生死鎖,但它也不能免疫。當您提出事件時,您所在的線程將執行任何代碼已註冊爲事件處理程序。該代碼並不特別。它只是在引發事件的同一個線程上執行的代碼。它可能會出現死鎖,或者出於所有相同的原因,任何代碼都可能死鎖。

問題是關於如何執行事件和事件處理程序的代碼沒有什麼特別的魔力。雖然我正在簡化到幾乎可以肯定是錯誤的地步,但基本原理是事件只是多播委託,可以將元素公開添加到調用列表中或從中刪除,但所有其他形式的訪問都是私有的。與線程相關的事件沒有任何關係。與在事件處理程序中以某種其他方式執行相同的代碼相比,使用事件不會影響死鎖的存在。

+0

爲了您的第一條評論,VS堆棧顯示籌集活動卡在外部電話。我認爲外部通話意味着它不是託管代碼。通常我期望事件不會返回,因爲事件處理程序的代碼是死鎖。除非VS沒有以某種方式顯示完整的堆棧。另外,連接事件處理程序的方式通常是+ =,沒有任何自定義事件訂閱代碼。 – dsum

+0

我的觀點只是事件與正常的代碼執行過程並沒有太大的不同,我將編輯我的答案以添加更多信息。通過外部呼叫,我假設你的意思是調用堆棧顯示'[External Code]'。外部代碼只是意味着Visual Studio不會將其視爲您的用戶代碼。您可以右鍵單擊調用堆棧窗口,然後從上下文菜單中選擇「顯示外部代碼」。當你這樣做時,你可能會看到一個'[Native to Managed Transition]',這是你離開託管代碼的地方。這可能會說明僵局的性質,或者不。 –