Являются ли эти частные статические члены потокобезопасными? - PullRequest
2 голосов
/ 20 февраля 2012

У меня есть следующий код с закрытыми статическими членами.

Все эти классы говорят, что они потокобезопасны в библиотеке 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);
    }
}

Ответы [ 3 ]

4 голосов
/ 20 февраля 2012

Ваш код не является потокобезопасным.

Рассмотрим переменную System.Text.Encoding enc. Вы звоните GetString, который является участником экземпляра. В документации говорится, что только общедоступные статические члены являются поточно-ориентированными, поэтому вывод GetString не является поточно-ориентированным, поскольку он не является общедоступным статическим элементом.

Этот код может не работать по следующим причинам:

  • Вы не пытались синхронизировать доступ к Encoding.GetString.
  • Encoding.GetString вызывается из открытого статического метода в вашем классе passwordManager.
  • Публичные статические методы имеют высокую вероятность одновременного выполнения несколькими потоками.

Причина, по которой публичные статические методы почти всегда разрабатываются для обеспечения безопасности потоков, заключается в том, что вызывающей стороне будет неудобно всегда синхронизировать доступ к ним. Вы не можете ограничить многопоточный доступ к статическим элементам, как вы можете с помощью элементов экземпляра. Рассмотрим приложение ASP.NET, например. Запросы веб-страниц часто обрабатываются одновременно в отдельных потоках. Вы хотите использовать lock каждый раз, когда вы вызываете статический метод? Конечно, нет. Это нелепое бремя для разработчика.

Обновление:

Ваш новый код теперь потокобезопасен. Вам нужно будет выполнить несколько тестов производительности, чтобы увидеть, какой путь быстрее: использовать lock или создавать новые экземпляры для каждого вызова, как сейчас. Я не удивлюсь, если бы lock были быстрее.


1 То же самое можно сказать о shaM.ComputeHash и enc.GetBytes.

4 голосов
/ 20 февраля 2012

безопасность потока не будет зависеть от того, является ли что-то частным или общедоступным.

Кстати, документ по безопасности потоков говорит, что все открытые статические члены из этого типа, а не когда этот тип встроен как открытая статическая.

Короче говоря, вы должны блокировать свои поля, как притворство, если вы многопоточны.

0 голосов
/ 20 февраля 2012

Возможно, вам лучше создать переменные уровня метода, чем пытаться синхронизировать доступ к общим закрытым полям. Таким образом, вы все равно достигнете параллелизма, поскольку каждый поток имеет свой собственный стек вызовов, поэтому будет иметь отдельные экземпляры каждого объекта и, таким образом, позволит нескольким потокам одновременно выполнять метод. Если вы заблокируете общий объект, тогда только один поток может выполнить метод одновременно. Другим вариантом может быть использование атрибута [ThreadStatic] в каждом поле, чтобы они не были общими для всех потоков.

...