2013-01-08 93 views
0

我一直在尋找這些問題從2009年: C# Events and Thread Safety多線程,競態條件和C#事件 - 爲什麼不嘗試/捕獲?

我也看了一下關於同一主題埃裏克利珀的博客文章: http://blogs.msdn.com/ericlippert/archive/2009/04/29/events-and-races.aspx

這個問題似乎歸結爲,在多線程環境中,你會偶爾會遇到這樣的情況:不同的線程在你的線程(線程A)'if'語句和'調用委託'語句之間取消了註冊委託。

當我讀到這個問題時,我想到了:如果候選對象似乎是競爭條件或拋出的異常之間的選擇,那麼爲什麼不把它包裝在try/catch塊中,而不用擔心要麼?如果你捕獲了nullReferenceException,只需在catch塊中忽略它(簡單地壓制異常)並繼續。

現在,我理解Eric Lippert和John Skeet對C#,多線程和委託人有一點了解,所以有人請花點時間解釋我在這裏失蹤的內容?

+2

如果在catch塊中你要做的所有嘗試/捕捉的重點是什麼? –

+0

問題的關鍵在於抑制一個異常,在這種情況下,您知道可以忽略,並且您不希望最終用戶必須重新啓動應用程序。另外,我沒有說「重新拋出」。我在哪裏說「扔掉」。顯然,我需要澄清這一說法。 – philologon

+6

我對這個問題感到困惑。捕捉異常如何消除競爭? –

回答

1

也許我理解你錯了,但你無法捕捉到每一個只是嘗試抓住比賽條件。看下面的代碼

int count = 0; 
for (int i = 0; i < 1000; i++) 
      Task.Factory.StartNew(()=>count++,TaskCreationOptions.LongRunning); 
Console.WriteLine(count); 

這可能會打印其他1000多次運行時。

+0

請注意我對我的評論給Eric Lippert的意見。我沒有清楚地思考,並且可能在發佈問題之前想了一會兒。因此,我沒有正確想到try/catch語句如何與競爭條件進行交互。 – philologon

+0

我選擇這個作爲接受的答案,因爲「我缺少的東西」是try/catch塊不會阻止競賽條件的發生,並且在答案級別的評論中,這是最接近我指出的。首先要做的是EricLippert,但他在評論中這樣做,而不是答覆,所以我不能將其標記爲Accepted。另外,其他的帖子也指出我沒有意識到的信息,所以謝謝大家的好評。 – philologon

2

這種異常吞嚥的主要問題是,您不能確定NullReferenceException是由事件代表null引起的。它可能是從代表本身中拋出的。

只是可以肯定 - 你說的是什麼,而不是這樣做:

Action temp = Foo; 
if (temp != null) 
     temp(); 

要做到這一點:

try { 
    Foo(); 
} 
catch (NullReferenceException e) 
{ 
    // magically ignore it 
} 

如此反覆,在Foo()調用可能引起類似的異常原因很多,你會掩蓋無關的例外情況。

+0

是的,你的代碼示例是我所描述的。 – philologon

+0

@philologon,好的,那麼正如我所說的,沒有辦法保證你正在捕捉的異常是由於競爭條件 - 可能是另一個原因 – sinelaw

2

一般來說,拋出異常時,表示發生了錯誤。

捕捉和異常不會使錯誤消失。您的操作仍然失敗。它所做的只是給你一個迴應發生錯誤的機會。

+0

如果在這種情況下可以捕獲一個特定的異常** **當特定的比賽情況發生時,可以抓住它。主要的一點是,即使這不是真的。 – sinelaw

2

如果交替似乎不是一個競爭條件或拋出的異常

我不認爲這是文章的點之間進行選擇。

正如埃裏克指出,有兩個問題:

  1. 委託可能是空
  2. 處理程序本身就可能在競爭條件;僅僅因爲註銷代碼類似event -= handler; DisposeRequiredResources();並不意味着處理程序代碼在調用dispose後不會運行。

問題1通常用臨時變量解決。 (由於競賽條件,需要if (Foo != null) Foo();不起作用)。其他解決方法包括使用空委託進行初始化。在這裏使用try/catch不僅僅是更多的輸入,它還有在事件處理程序中吞噬實際NullReferenceExceptions的危險。

問題2是通過使處理程序健壯來解決的。將整個調用放在try/catch塊中並不能緩解這個問題。