2014-11-06 59 views
3

在衆所周知的Joseph Albahari's article on Threading中,多線程使用的所有類變量被聲明爲static fields =>所有線程都可以訪問相同的變量。這需要通過lock()機制在所有的閱讀/寫作地點配備,並完成工作。在多線程中共享數據 - 是非靜態變量嗎?

我的問題是關於類屬性的實現。我明白,如果我實現(例如)使用static後備存儲性能Timeout它是有效的:

class MyClassWithWorkerThread { 
    private readonly object _locker = new object(); 
    private static int _Timeout = false; 
    private int Timeout { 
     get { 
      lock (_locker) { 
       return _Timeout; 
      } 
     } 
     set { 
      lock (_locker) { 
       _Timeout = value; 
      } 
     } 
    } 
} 

這將使變量_Timeout所有的類實例共享。

但在我的情況下,多線程處理是類實例私有的。它始於New()並以Dispose()結束。主線程和工作線程都訪問Timeout屬性(但_Timeout後備存儲從不在屬性getter/setter之外訪問)。我不希望_Timeout值在應用程序範圍內。我希望每個類實例都具有唯一的 我的問題是:我可以安全地從_Timeout變量中刪除static以實現此目的嗎?

注意:如果代碼中有任何錯誤,我很抱歉,實際上我使用VB.NET,並使用工具對其進行了轉換。我希望主要問題仍然清楚。

回答

3

絕對安全和漂亮的建議(靜態變量是痛苦的測試,即使需要)。與安全假設你也意味着有效你沒有忘記的是:

this.Timeout = 0; // This is safe and valid 
++this.Timeout; // This is safe but not valid 

因爲++操作不是原子的(這就是爲什麼我們有Interlocked類)。當然,同樣在這種情況下適用於:

if (this.Timeout == 0) 
    Timeout = 10; 

因爲即使每個接入是安全(我會說讀屬性始終是安全的,但你可以閱讀沒有lock屏障的舊值),它不是一個原子操作並且在測試之後和新分配之前價值可能會改變。更復雜?

if (this.Timeout == 0) 
    Timeout = Timeout * 2; 

在這種情況下,每次讀取時間Timeout你可能會得到不同的值。由於這個原因,我說鎖定屬性很少有用,除非它是一個只讀屬性。好得多移除屬性get/set的鑰匙,在lock語句包住代碼:

lock (_locker) { 
    if (this.Timeout == 0) 
     Timeout = Timeout * 2; 
} 

另請注意,int _Timeout(我假設有false分配僅僅是一個錯字),你可以簡單地刪除鎖,使它volatile

private volatile int _Timeout; 

當然,這將不能解決其它描述的問題,但它可能是有用的(更快),用於只讀屬性(或對於相當控制的情況下,改性劑volatile可以是棘手的,它與C相比有不同的含義,很容易忘記t帽子訪問他們是原子,但沒有更多)。

+0

我完全同意使用'lock()'(VB:'SyncLock ... End SyncLock')塊來描述。我實際上是想通過在需要的地方創建'Timeout'的本地副本(通過單個讀取操作)來避免突出顯示的場景,因爲在類方法內部沒有寫入它。我在問題中沒有說清楚,但我理解鎖定概念。但至少其他讀者會從你的詳細答案中受益,所以謝謝。 – miroxlav 2014-11-06 12:43:17

+0

易變的場* *非常原子。顯然按順序執行兩個操作不是原子操作,但是也不是按順序鎖定兩次。 – Voo 2014-11-06 17:26:51

+0

@Voo你是對的,我的句子很不明確:對volatile變量的訪問是原子操作,但是_seems_執行原子操作的操作符不是(比如++)​​。 – 2014-11-06 18:44:42

1

static關鍵字是正交的(即:獨立或不相關)線程。

static關鍵字只應該在你只需要該屬性/ field/class/method/etc的單個實例時使用。

在您的情況下,如果您希望該值對實例唯一,則不需要_Timeout上的靜態值。

我沒有看到你的文章鏈接,但我認爲你可能誤會它(或作者誤解了使用靜態)

+0

雖然被引用的文章非常好,並被許多人推薦,但我發現'靜態'在那裏有點過分使用,即使在不一定需要的情況下也是如此。但是現在,這個觀點已經明確,謝謝。 – miroxlav 2014-11-06 12:38:53

+0

@miroxlav是的,我猜他幾乎在任何地方都使用了靜態的_simplicity_,並保持代碼樣本更短(沒有實例對象來創建和傳遞)。從簡單的看,我認爲這不是他建議的線程,只是一個方便的語法。 – 2014-11-06 12:45:17