Вопрос

Моя команда в настоящее время обсуждает этот вопрос.

Код, о котором идет речь, представляет собой что-то вроде

if (!myDictionary.ContainsKey(key))
{
    lock (_SyncObject)
    {
        if (!myDictionary.ContainsKey(key))
        {
            myDictionary.Add(key,value);
        }
    }
}

В некоторых постах, которые я видел, говорится, что это может быть большим "НЕТ-НЕТ" (при использовании TryGetValue).Тем не менее, члены нашей команды говорят, что это нормально, поскольку "containsKey" не выполняет итерацию набора ключей, а проверяет, содержится ли ключ с помощью хэш-кода в O(1).Поэтому они утверждают, что здесь нет никакой опасности.

Я хотел бы узнать ваше честное мнение по этому вопросу.

Это было полезно?

Решение

Не делай этого.Это небезопасно.

Ты мог бы звонить ContainsKey из одного потока, в то время как другой поток вызывает Add.Это просто не поддерживается Dictionary<TKey, TValue>.Если Add нужно перераспределить ведра и т.д., я могу себе представить, что вы мог получите какие-то очень странные результаты или исключение.Оно мочь были написаны таким образом, что вы не видите никаких неприятных эффектов, но я бы не хотел полагаться на это.

Одно дело использовать блокировку с двойной проверкой для простого чтения / записи в поле, хотя я бы все равно возражал против этого - совсем другое - выполнять вызовы API, который был явно описан как нет быть безопасным для нескольких одновременных вызовов.

Если вы используете .NET 4, ConcurrentDictionary вероятно, это путь вперед.В противном случае просто заблокируйте каждый доступ.

Другие советы

Если вы находитесь в многопоточной среде, вы можете предпочесть посмотреть с использованием CONDURMENTDICTICE.Я провожу об этом пару месяцев назад, вы можете найти статью полезную: http://colinmackay.co.uk/blog/2011/03/24/paralliasation-in-net-4-0-the-concurrent-dictionary/>

Этот код неверен.То Dictionary<TKey, TValue> type не поддерживает одновременные операции чтения и записи.Даже несмотря на то, что ваш Add метод вызывается внутри блокировки, в которой ContainsKey не является.Следовательно, это легко допускает нарушение правила одновременного чтения / записи и приведет к повреждению в вашем экземпляре

Это не выглядит безопасно, но, вероятно, было бы трудно сделать его сбой.

Итерация VS Ashh Assup Argust не держит, например, может быть хэш-столкновение.

Если этот словарь редко написан и часто читает, то я часто использую безопасную двойную блокировку, заменив весь словарь на запись. Это особенно эффективен, если вы можете писать вместе, чтобы сделать их менее частыми.

Например, это срезанная версия способа, который мы используем, который пытается получить объект схемы, связанного с типом, и если он не может, то он идет вперед и создает объекты схемы для всех типов, которые он находит В той же сборке, что и указанный тип, чтобы минимизировать количество раз, весь словарь должен быть скопирован:

    public static Schema GetSchema(Type type)
    {
        if (_schemaLookup.TryGetValue(type, out Schema schema))
            return schema;

        lock (_syncRoot) {
            if (_schemaLookup.TryGetValue(type, out schema))
                return schema;

            var newLookup = new Dictionary<Type, Schema>(_schemaLookup);

            foreach (var t in type.Assembly.GetTypes()) {
                var newSchema = new Schema(t);
                newLookup.Add(t, newSchema);
            }

            _schemaLookup = newLookup;

            return _schemaLookup[type];
        }
    }
.

Так что словарь в этом случае будет восстановлен, не более, столько раз, сколько есть сборки с типами, которые нуждаются в схемы. Для остальной части приложения срок службы доступные доступ к словарю будут без блокировки. Словарь Copy становится единовременной стоимостью инициализации сборки. Словарь Swap является безопасным потоком, потому что пишет указатель, атомные, поэтому вся ссылка переключается одновременно.

Вы можете применить аналогичные принципы в других ситуациях.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top