2012-02-20 83 views
2

我有以下代碼與私有靜態成員。這些私有靜態成員是否線程安全?

所有這些類都表示它們在MSDN庫中對於「public static」成員是線程安全的。

我的問題是,這些成員將作爲私有靜態而不是「MSDN庫中所述的」公共靜態「時使用線程安全。

public static class passwordManager 
{ 
    private static System.Security.Cryptography.SHA256 shaM = new System.Security.Cryptography.SHA256Managed(); 
    private static System.Security.Cryptography.RandomNumberGenerator rand = new System.Security.Cryptography.RNGCryptoServiceProvider(); 
    private static System.Text.Encoding enc = System.Text.Encoding.ASCII; 

    public static string produceSalt(int size) 
    { 
     byte[] by = new byte[size]; 
     lock (rand) 
     { 
      rand.GetBytes(by); 
     } 
     return enc.GetString(by, 0, by.Length); 
    } 

    public static string encryptPassword(string password, string salt){ 

     return enc.GetString(shaM.ComputeHash(enc.GetBytes(password + salt))); 
    } 

    public static bool isCorrectPassword(string inputPassword, string DBsalt, string DBpassword) 
    { 
     return encryptPassword(inputPassword, DBsalt) == DBpassword; 
    } 

這可能是完全依賴於是否我的方法,我用自己使用共享變量,而不是所有的方法實例變量...一些安心將是有益的,但我寧可不要在這裏如果一切鎖這是沒有必要的。

我鎖定隨機數生成器的唯一原因是爲了限制獲得同樣的鹽的可能性,但同時這兩個線程調用的機會在我的情況下非常低。

感謝,

邁克

這個現在應該是線程安全的。我試圖保存對象實例化的開銷,但我想這和鎖等待之間有一個權衡。在高負載系統上,等待鎖定可能會大大超過實例化開銷和內存使用量。

public static class passwordManager 
{ 
    private static System.Security.Cryptography.RandomNumberGenerator rand = new System.Security.Cryptography.RNGCryptoServiceProvider(); 

    public static byte[] produceSalt(int size) 
    { 
     byte[] by = new byte[size]; 
     lock (rand) 
     { 
      rand.GetBytes(by); 
     } 

     return by; 
    } 

    public static byte[] encryptPassword(string password, byte[] salt){ 

     System.Security.Cryptography.SHA256 shaM = new System.Security.Cryptography.SHA256Managed(); 
     System.Text.Encoding enc = new System.Text.UTF8Encoding(); 

     return shaM.ComputeHash(concatArrays(enc.GetBytes(password), salt)); 
    } 

    public static bool isCorrectPassword(string inputPassword, byte[] DBsalt, byte[] DBpassword) 
    { 
     return compare(encryptPassword(inputPassword, DBsalt), DBpassword); 
    } 
} 
+0

對不起,我誤解了MSDN庫的術語。 – 2012-02-20 17:39:12

回答

4

您的代碼不是線程安全的。

考慮System.Text.Encoding變量enc。您正在調用GetString這是一個實例成員。該文檔說只有公共靜態成員是線程安全的,因此推理GetString不是線程安全的,因爲它不是公共靜態成員。

此代碼可能會由於以下原因:

  • 你沒有嘗試同步訪問Encoding.GetString
  • Encoding.GetString從您的passwordManager類的公共靜態方法中調用。
  • 公共靜態方法很有可能被多個線程同時執行。

爲什麼公共靜態方法幾乎總是被設計爲線程安全的原因是因爲調用方始終同步對它的訪問會很尷尬。您不能像使用實例成員一樣限制對靜態成員的多線程訪問。例如,考慮一個ASP.NET應用程序。網頁請求經常在不同的線程上同時處理。你想每次使用lock你調用一個靜態方法嗎?當然不是。這對開發人員來說是一個荒謬的負擔。

更新:

你的新代碼現在是線程安全的。您將不得不做一些基準測試,以查看哪種方式更快:使用lock或在每次調用中實例化新實例,就像現在一樣。如果lock速度更快,我不會感到驚訝。


同樣可以說爲shaM.ComputeHashenc.GetBytes

+0

是的,我相信它會快得多,但是在極端負載的情況下,只要有足夠的服務器資源,對單個靜態對象的鎖定可能比創建新對象要慢得多。 我的用例處於非常低的負載情況下,所以任何一種方式都會足夠快速且響應。 – 2012-02-27 06:45:05

4

線程安全不會取決於某些東西是私有的還是公共的。

順便說一句,線程安全文件說這個類型的任何公共靜態成員,而不是當這種類型嵌入爲公共靜態。

總之,如果你是多線程的,你必須鎖定你的領域像假。

0

您可能更適合創建方法級別的變量,而不是嘗試同步對共享私有字段的訪問。這樣,您仍然可以實現併發性,因爲每個線程都有自己的調用堆棧,因此每個對象都有獨立的實例,因此允許多個線程同時執行該方法。如果您鎖定共享對象,則一次只能有一個線程執行該方法。另一種選擇可能是在每個字段上使用[ThreadStatic]屬性,以便它們不會在線程間共享。