2012-02-20 109 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]属性,以便它们不会在线程间共享。