2010-07-22 2 views
3

У меня есть отображение, в котором каждая клавиша может иметь несколько связанных значений. Я думал, что ConcurrentDictionary может помочь мне более легко скопировать эту карту для использования в многопоточной среде, но методы, похоже, построены вокруг одного значения. Я вижу, что AddOrUpdate() позволяет мне изменять значение, если оно уже существует, но оно не гарантирует атомарность для этой операции, поэтому кажется бессмысленным? У кого-нибудь есть хорошая стратегия для решения этой ситуации?Можете ли вы использовать ConcurrentDictionary для сопоставления «один ко многим»?

Извините, я думаю, я был немного расплывчатым. Я хотел бы иметь несколько значений для ключа, т. Е. Иметь IList, связанный с ключом. Но я хочу иметь возможность добавлять/удалять значения из многозначного значения безопасным образом. Это похоже на то, что метод AddOrUpdate + delegate может привести к потерям, если несколько вызовов к нему были сделаны в одно и то же время?

+0

У вас уже был C# в тегах. Вам также не нужно было указывать его в названии. Кроме того, ваш вопрос не имеет ничего общего с C# 4.0. –

ответ

1

Я думал, что AddOrUpdate был атомарным, но похоже, что он не является атомарным относительно делегата. Сожалею!

Ссылка, которая может помочь: http://blogs.msdn.com/b/pfxteam/archive/2009/11/06/9918363.aspx

+0

Вы ошибаетесь. В документации указано, что вызов делегата НЕ производится под блокировкой из-за непредсказуемости кода пользователя. – evilfred

+0

Из вашей ссылки: «Атомная по отношению к другим методам мутации в коллекции (например, TryAdd/TryUpdate/TryRemove/etc.), За исключением выполнения предоставленного пользователем делегата». – evilfred

+0

ОК, я понимаю, что вы имеете в виду. Я просмотрел его и неверно истолковал. Отредактированный пост для размышлений. – mquander

0

Похоже, оба AddOrUpdate и TryUpdate будет работать.

редактировать

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

public TValue AddOrUpdate(TKey key, Func<TKey, TValue> addValueFactory, Func<TKey, TValue, TValue> updateValueFactory) 
{ 
    TValue local; 
    TValue local3; 
    if (key == null) 
    { 
     throw new ArgumentNullException("key"); 
    } 
    if (addValueFactory == null) 
    { 
     throw new ArgumentNullException("addValueFactory"); 
    } 
    if (updateValueFactory == null) 
    { 
     throw new ArgumentNullException("updateValueFactory"); 
    } 
    do 
    { 
     if (!this.TryGetValue(key, out local3)) 
     { 
      TValue local2; 
      local = addValueFactory(key); 
      if (!this.TryAddInternal(key, local, false, true, out local2)) 
      { 
       continue; 
      } 
      return local2; 
     } 
     local = updateValueFactory(key, local3); 
    } 
    while (!this.TryUpdate(key, local, local3)); 
    return local; 
} 

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

+0

Почему TryAddInternal возвращает что-то отличное от того, что мы вставляем? – evilfred

+0

Скорее всего TryAddInternal возвращает фактическое значение для ключа, независимо от того, возвращает ли оно false (то есть - независимо от того, был ли добавлен второй параметр или нет). –

+1

Если мы не знаем, что TryAddInternal делает, то чтение этого кода похоже на чтение чайных листьев. – evilfred

Смежные вопросы