2014-12-20 45 views
5

我目前正在閱讀Joe Albahari的Threading in C#電子書,有時在他的示例代碼中,他在沒有看到任何線程安全問題的地方使用鎖。例如,他鎖定寫入_status字段並從中讀取_status字段,該字段指的是不可變對象。爲什麼在這裏使用鎖?

我明白,如果ProgressStatus類是可變,你就需要鎖定圍繞讀取和寫入到它,因爲如果一個線程是捷足先登被另一個線程讀取更新PERCENTCOMPLETE和StatusMessage場之間狀態,第二個線程可能會爲這些字段獲取一對無效值。 (100%完成/「操作正在進行中......」)

但由於ProgressStatus是不變的,不會發生這樣的無效狀態。如果Joe刪除了這兩個鎖,那麼會出現什麼線程安全問題?

回答

4

如果喬除去這兩個鎖的,可能出現什麼的線程安全問題?

它可能會導致「陳舊的數據」,閱讀代碼可以緩存它,只能看到舊值。

lock的這種用法是典型的,它從lock的副作用中獲益:它具有隱含的內存屏障,並且防止看到舊副本。你會更通常看到volatile ProgressStatus _status;,但volatile也有其問題。

你是正確的,實際的讀寫操作不reallly這裏需要一個鎖(acessing一提的是原子)。

+0

謝謝 - 我懷疑一個易變的字段可能會訣竅。 「'volatile'也有問題」 - 你能否詳細說明一下? – dgmulf

4

讀者可能永遠也看不到_status升級到一個新的值,例如。所有讀取可能會摺疊成一個物理讀取。

另外,我覺得你可能會看到部分初始化對象的情況下,_status致力於內存被引用的對象中的字段之前。

請注意,此鎖定與被引用的對象無關。這是關於保護參考本身。

訪問在多個線程變量時的訪問之一是寫是數據競爭。各種各樣的事情都可能發生。我上面所說的只是例子。

+0

謝謝。但是,在我看來,您提到的兩個問題都可以通過使用「易失性」字段或內存屏障來更明確地解決。如我錯了請糾正我。 – dgmulf

+1

是的,他們可以用volatile來解決,但這很難理解。如果性能需求需要,應使用複雜的基元。 – usr

+1

在這個特定情況下使用內存障礙的一個問題是,它將意味着使用文章的第2部分中的東西,直到第4部分才被解釋。 –