【问题标题】:Are these private static members thread safe?这些私有静态成员线程安全吗?
【发布时间】:2012-03-10 13:13:40
【问题描述】:

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

所有这些类都表示它们在 MSDN 库中对于“公共 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);
    }
}

【问题讨论】:

  • 抱歉,我误解了 MSDN 库的术语。

标签: c# multithreading static private


【解决方案1】:

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

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

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

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

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

更新:

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


1shaM.ComputeHashenc.GetBytes 也是如此。

【讨论】:

  • 是的,我相信它会快得多,但是在极端负载情况下,锁定单个静态对象可能比创建新对象慢得多,只要它们有足够的服务器资源。我的用例处于非常低负载的情况下,因此任何一种方式都足够快速且响应迅速。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    线程安全不取决于某些东西是私有的还是公共的。

    顺便说一句,线程安全文档说这种类型的任何公共静态成员,而不是当这种类型作为公共静态嵌入时。

    简而言之,如果您使用多线程,则必须像假一样锁定您的字段。

    【讨论】:

      猜你喜欢
      • 2011-01-28
      • 2013-12-10
      • 2019-05-21
      • 2010-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-08
      • 2016-07-16
      相关资源
      最近更新 更多