2016-02-22 56 views
3

我正在尋找爲什麼Microsoft建議的對象編碼事件訪問語法時鎖定的其他信息。微軟的代碼示例如下所示,並且建議被鏈接到。多線程的擔憂時編碼事件訪問

我理解有關鎖定一段代碼以控制對其的多線程訪問的一般概念,但是我正在尋找特定的原因,以便在Microsoft的上下文中編寫自定義事件訪問器邏輯示例顯示。

以下示例說明如何實現自定義添加和刪除事件訪問器。儘管您可以替換 訪問器中的任何代碼,但我們建議您在添加事件之前先鎖定事件,或者刪除新的事件處理程序方法。

event EventHandler IDrawingObject.OnDraw 
    { 
     add 
     { 
      lock (PreDrawEvent) 
      { 
       PreDrawEvent += value; 
      } 
     } 
     remove 
     { 
      lock (PreDrawEvent) 
      { 
       PreDrawEvent -= value; 
      } 
     } 
    } 

〜通過https://msdn.microsoft.com/en-us/library/bb882534.aspx?f=255&MSPPError=-2147217396

+0

在事件發生的同時,事件句柄是否可以被移除?會猜測這可能會導致空引用異常。 –

+0

我不是100%確定,但我認爲這是因爲一個事件基本上是一個多播委託。因此,當您添加/刪除處理程序時,實際會創建* new *委託。所以,它實際上是一個兩步操作:生成新的委託,並分配給現有的變量。如果多個線程同時(不)訂閱,那麼會引入競爭條件的窗口。 –

+2

還有一點需要注意的是,由於上述原因,我認爲鎖定正在修改的事件將會是一個糟糕的形式。有一個專門的鎖對象似乎更明智。 –

回答

1

只有MSDN文章的作者可以爲您提供一個明確的答案,文章的措辭。

但是:在我看來,對於諮詢的首要原因是,代碼幾乎總是使用編譯器提供的事件訪問方法。這些一直都是100%線程安全的,並且隨着編譯器的最近變化(我認爲是C#4,但我不確定),它們實際上是。

使用默認實現線程安全的原因是,我認爲不言自明:這樣做涉及合理的低成本,並且需要事件訪問器方法中的線程安全性足夠頻繁,迫使開發人員實現它們每次他們需要線程安全時自己的訪問者將是不合理的。

因此,考慮到默認實現是線程安全的,這意味着事件的消費者(通常不會隨時訪問事件的源代碼)將習慣於假定事件訪問器是總是線程安全。違反這個假設會導致代碼中有錯誤。底線:如果您100%確定您的事件只能在單個線程中訪問,或者至少以線程安全的方式訪問,那麼您可以在訪問器方法中不添加明確的線程安全性的情況下離開。問題在於,達到這種100%確定性是可疑的有效性;要預測如何使用特定的代碼幾乎是不可能的,尤其是將來人們所談論的更遠。

代碼能活一個令人驚訝的很長一段時間。最好確保它能夠處理拋出它的東西,尤其是當代碼的未來客戶完全有理由認爲代碼可以處理它時。


另外:雖然MSDN顯示鎖定事件字段本身,但這對我來說似乎有問題。字段更新的那一刻,即使鎖本身沒有退出,任何當前保持的鎖也不會阻止隨後執行代碼進入鎖。在某些平臺上可能存在字段可見性問題,這是由於讀取和寫入到字段的錯誤排列;這可能導致兩個隨後執行的線程查看鎖的不同值,然後同時輸入受保護的部分。

沒關係使用公開可用的值進行鎖定的更普遍的問題。關於該特定主題存在一些爭議,但我傾向於只使用私有值進行鎖定。即不要使用事件字段的當前值鎖定(因爲它是可更改的),也不會使用this(因爲它是公開的)來鎖定。