2016-03-03 64 views
22

提前道歉:這個問題來自於一個努力學習高級C#的硬核,未改編的C++開發人員。考慮以下內容:是C#6嗎? (貓王op)線程安全嗎?如果是這樣,怎麼樣?

if (myUserDefinedObject != null) 
{ 
    myUserDefinedObject.ToString(); 
} 

這顯然不是線程安全的。另一方面,我見過兩篇教程說? (消零條件運算符或 '貓王運營商')例如,

myUserDefinedObject?.ToString(); 

IS線程安全的。除非編譯器在封面(shiver)下包裹一個[mutex?]鎖定,否則我不明白這是怎麼回事。如果這個習語是線程安全的,那麼有人能夠指出我是如何完成該技術的技術描述的?如果它不是線程安全的,有沒有人有一個實際上說它不是?

+3

對不起,但您的第一個代碼塊可以完全線程安全,具體取決於使用它的上下文和變量的範圍。 –

+2

@KenWhite - 我認爲第一個塊的想法是,另一個線程可能會在檢查之後但在.ToString()導致代碼失敗之前將該變量設置爲null。我會說它不是線程安全的。 – Enigmativity

+0

@Enigmativity:海報明確表示,該代碼塊是**不是線程安全**,如果不知道上下文或範圍,這不是一個準確的陳述。我指出,該聲明是不準確的 - 這是不真實的,該塊中的代碼明確不是線程安全的。 –

回答

24

MSDN(重點煤礦):

爲空狀態成員訪問的另一個用途是用更少的代碼調用代表以線程安全的方式。舊的方式需要像下面的代碼:

var handler = this.PropertyChanged; 
if (handler != null) 
    handler(…) 

的新方法則簡單得多:

PropertyChanged?.Invoke(e) 

的新方法是線程安全的,因爲編譯器生成的代碼只能評估的PropertyChanged一次,將結果保留在臨時變量中。

所以沒有這裏涉及到鎖定 - 線程安全性是通過創建一個本地臨時變量,以防止不同的線程修改變量空校驗和其他一些操作之間執行。

+6

因此,它是如何線程安全的取決於你想要做什麼。如果另一個線程調用Dispose(),您可能會得到一個ObjectDisposedException,但您不會在調用站點獲得空指針異常。 –

+0

我會更傾向於相信MSDN文檔,如果有人能夠解釋在C#中,如何在內存地址檢查爲非零時,以及在嘗試訪問內容時未知的某些未知時間該地址的內容未被修改。從我上面引用的文章中,我們知道可以使用* hardware *來標記該位置(使用atomics,memory_modes等)。那是「編譯器」在做什麼? @Hank,你也可能會得到一個答案 - 而不是你期待的對象仍然在那個位置。 ;-) –

+3

這是不是真的線程安全,因爲[說明](https://msdn.microsoft.com/en-us/magazine/jj883956.aspx)請參閱「閱讀簡介」部分。 JIT有時可以完全消除局部變量並將另一個讀取引入實際字段。 –

28

我想澄清BJ Myers的(正確)答案。

在C#中,一個事件可以被認爲是一個委託類型的字段 - 正如一個屬性可以被認爲是屬性類型的一個字段 - 並且該「字段」的值可以爲null。如果你是有被修改在一個線程中的事件處理程序,而另一個線程試圖調用它的不幸的情況,你可以進入情況:

if (this.SomeEvent != null) 
    this.SomeEvent(...); 

不是線程安全的。該值可能會發生變化,以便在檢查之前爲非空,在檢查之後爲空,並且程序崩潰。

使這個「線程安全」,我使用術語通常,通常的方法是將值複製到本地,然後測試本地爲空。這具有不會導致null解除引用的好處。但是,聰明的開發者會注意到還有一場比賽!該序列可以緩存在線程

  • 非空的事件處理程序
  • 事件處理程序設置爲null的線程B
  • 的事件處理程序需要被銷燬線程B國
  • 事件處理程序運行在線程A並死亡可怕

因此,在這個意義上這種模式不是「線程安全」的。如果您處於這個不幸的位置您有責任確保實施適當的線程邏輯,以便不會發生這種情況。無論你想要什麼,你都可以做到。如果你希望能夠在一個線程上調用事件處理程序(在另一個線程上改變事件)時獲得(可疑的)好處,那麼你必須付出代價才能使其安全或處理競態條件錯誤。

我個人會避免像鼠疫這種情況,但我不夠聰明,寫出正確的多線程代碼。

現在,作爲實際的問題:

some_expression ?. ToString(); 

相同

temp = some_expression 
temp == null ? null : temp.ToString() 

是在您看來,後者的代碼 「線程」?

+0

偉大的評論在這裏 - 感謝您的優秀解釋。 「線程安全性」完全取決於線程使用代碼的方式。 –

+0

那麼......不安全嗎?還是它?我們是否需要使用一個鎖來避免崩潰,如果我們有多個線程在亂搞? – Narvalex

+4

@Narvalex:我應該怎麼知道?解釋*你在哪裏放置鎖*,以及*鎖可以防止什麼競爭*,以及*你的策略是爲了避免死鎖*,然後我們可以在決定你的解決方案是否正確時做出一些決定。請記住,*線程安全性是整個程序的屬性*,因此如果您想知道某個程序是否是線程安全的,則必須提供整個程序的詳細信息。 *這就是爲什麼線程很難*。你拿着一塊磚,問「這塊磚是用結構上的聲音做成的房子嗎?」這是房子的財產,而不是磚頭。 –

相關問題