这些私有静态成员是否安全?

时间:2012-02-20 06:25:58

标签: c# multithreading static private

我有以下私有静态成员的代码。

所有这些类都表示它们在MSDN库中对于“公共静态”成员是线程安全的。

我的问题是这些成员在用作私有静态时是否是线程安全的,而不是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);
    }
}

3 个答案:

答案 0 :(得分:4)

线程安全不取决于某些内容是私有的还是公开的。

BTW,线程安全文档说明此类型的任何公共静态成员,而不是当此类型作为公共静态嵌入时。

简而言之,如果你是多线程的话,你必须像sham一样锁定你的字段。

答案 1 :(得分:4)

您的代码不是线程安全的。

考虑System.Text.Encoding变量enc。您正在调用GetString,它是一个实例成员。文档说只有公共静态成员是线程安全的,因此推断GetString不是线程安全的,因为它不是公共静态成员。 1

此代码可能由于以下原因而失败:

  • 您未尝试同步Encoding.GetString
  • 的访问权限
  • Encoding.GetString是从passwordManager类中的公共静态方法调用的。
  • 公共静态方法很可能同时由多个线程执行。

公共静态方法几乎总是被设计为线程安全的原因是因为调用者总是同步访问它是不方便的。您不能像实例成员那样限制对静态成员的多线程访问。例如,考虑一个ASP.NET应用程序。网页请求经常在不同的线程上同时处理。您是否希望每次使用lock 调用静态方法?当然不是。这对于开发人员来说是一个荒谬的负担。

<强>更新

您的新代码现在是线程安全的。您将不得不进行一些基准测试以查看哪种方式更快:使用lock或在现有的每次调用中实例化新实例。如果lock更快,我不会感到惊讶。


1 对于shaM.ComputeHashenc.GetBytes也可以这样说。

答案 2 :(得分:0)

您最好创建方法级变量,而不是尝试对共享私有字段进行同步访问。这样,您仍然可以实现并发,因为每个线程都有自己的调用堆栈,因此每个对象都有单独的实例,因此允许多个线程同时执行该方法。如果锁定共享对象,则一次只能有一个线程执行该方法。另一种选择可能是在每个字段上使用[ThreadStatic]属性,这样它们就不会在线程之间共享。