Я полагаю, что это работает, я протестировал его с несколькими параллельными потоками (хотя не исчерпывающе для условий состязания и мертвых блокировок):
public static System.Collections.Concurrent.ConcurrentDictionary dict =
new System.Collections.Concurrent.ConcurrentDictionary();
public static item dump;
...
foreach (System.Collections.Generic.KeyValuePair x in dict)
{
lock (x.Value)
{
if (x.Value.IsCompleted)
{
dict.TryRemove(x.Key, out dump);
}
}
}
Этим вопросом является вид продолжения этого вопроса:
Я могу удалить объекты из ConcurrentDictionary из цикла перечисления того словаря?
И этот вопрос:
Обновление полей значений в ConcurrentDictionary
В этом я делаю два "рискованных" маневра:
ConcurrentDictionary
одновременно перечисляя через него (который, кажется, в порядке).Value
часть a ConcurrentDictionary
. Необходимый, потому что управление полями значения не ориентировано на многопотоковое исполнение, только управляя самими значениями ConcurrentDictionary
ориентировано на многопотоковое исполнение (код выше является отрывком большего блока кода, в котором полями значений на самом деле управляют).Удаление значений из параллельного словаря во время итерации по нему - это нормально. Это может иметь некоторые последствия для производительности (я не уверен), но это должно работать.
Обратите внимание, что вы не блокируете что-то внутреннее в ConcurrentDictionary
- вы блокируете монитор, связанный с объектом item
. Я бы лично не хотел этого делать: либо эти элементы должны быть потокобезопасными (что позволяет манипулировать ими в любом случае), либо (предпочтительнее) неизменяемыми, чтобы вы могли наблюдать их из любого потока без блокировки. Или вы можете просто сделать отдельное свойство, которое вы проверяете, потокобезопасным, конечно. Документируйте все, что вы делаете!
Наконец, ваше использование out dump
кажется несколько сомнительным. Смысл в том, чтобы было что передать TryRemove
? Если да, то я бы использовал локальную переменную вместо статической.