Статические методы обновления словаряв ASP.NET - безопасно ли блокировать () самого словаря? - PullRequest
5 голосов
/ 23 декабря 2010

У меня есть класс, который поддерживает статический словарь результатов поиска в кэше с моего контроллера домена - имена пользователей и электронные письма.

Мой код выглядит примерно так:

private static Dictionary<string, string> emailCache = new Dictionary<string, string>();

protected string GetUserEmail(string accountName)
{
    if (emailCache.ContainsKey(accountName))
    {
        return(emailCache[accountName]);
    }

    lock(/* something */)
    {
        if (emailCache.ContainsKey(accountName))
        {
            return(emailCache[accountName]);
        }

        var email = GetEmailFromActiveDirectory(accountName);
        emailCache.Add(accountName, email);
        return(email);
    }
}

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

Если требуется блокировка , нужно ли создавать выделенный экземпляр статического объекта для использования в качестве токена блокировки, или безопасно использовать фактический экземпляр словаря в качестве токена блокировки?

Ответы [ 6 ]

5 голосов
/ 23 декабря 2010

Коллекции в .NET не являются поточно-ориентированными, поэтому блокировка действительно требуется. Альтернативой использованию словаря может быть использование параллельных словарей, представленных в .NET 4.0

http://msdn.microsoft.com/en-us/library/dd287191.aspx

1 голос
/ 23 декабря 2010

В документации MSDN указано, что вы никогда не должны использовать оператор lock () для открытого объекта, который может быть прочитан или изменен вне вашего собственного кода.

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

Я могу ошибаться, я не писал строки C # с год назад.

1 голос
/ 23 декабря 2010

Так как словарь является частным, вы должны безопасно его заблокировать.Опасность блокировки (о которой я знаю) состоит в том, что другой код, который вы сейчас не рассматриваете, может также заблокировать объект и потенциально привести к тупику.С частным словарем это не проблема.

Честно говоря, я думаю, что вы могли бы снять блокировку, просто изменив свой код, чтобы он не вызывал метод Add из словаря, вместо этого используя оператор набора свойств.Тогда я вообще не верю в блокировку.

ОБНОВЛЕНИЕ: Ниже приведен блок кода из закрытого метода вставки в словаре, который вызывается как установщиком элементов, так иДобавить метод.Обратите внимание, что при вызове из установщика элементов переменная «add» устанавливается в значение false, а при вызове из метода Add переменная «add» устанавливается в значение true:

if (add)
{
    ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate);
}

Так что мне кажется,что если вас не беспокоит перезапись значений в вашем словаре (чего в этом случае не было бы), тогда достаточно использовать установщик свойств без блокировки.

1 голос
/ 23 декабря 2010

Да, блокировка требуется до тех пор, пока код в других потоках может / будет получать доступ к статическому объекту.

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

1 голос
/ 23 декабря 2010

Блокировка действительно требуется.

Используя блокировку, вы гарантируете, что только один поток может одновременно получить доступ к критической секции, поэтому дополнительный статический объект не нужен.1005 *

Вы можете заблокировать сам объект словаря, но я бы просто использовал object lock =new object(); в качестве моей блокировки.

0 голосов
/ 23 декабря 2010

Насколько я мог видеть, дополнительный object в качестве мьютекса был использован:

private static object mutex = new object();

protected string GetUserEmail(string accountName)
{
    lock (mutex)
    {
        // access the dictionary
    }
}
...