Словарь безопасности параллельного использования
Мне нужно поточно-безопасный способ получить каждый элемент ConcurrentDictionary(строка, список)
Безопасно ли использовать следующую конструкцию?
foreach (var item in concurrentDict)
{
var readonlyCollection = item.Value.AsReadOnly();
//use readonly collection, (I need only Values of the concurrent dictionary)
}
Я хочу использовать значения словаря безопасности.
1 ответ
foreach
с частью все в порядке, с оговоркой, что одновременно добавленные элементы могут или могут быть отмечены как включенные в итерацию. Вы не получите исключения, хотя.
Тем не менее, вы должны быть осторожны с item.Value
, который имеет тип List
потому что списки не потокобезопасны. Если другой поток изменяет список, пока вы читаете его в цикле, вы можете получить исключение.
призвание AsReadOnly()
в вашем списке не поможет, потому что вы получаете обратно обертку для первоначального списка. Если чтение из исходного списка внутри обертки выбрасывает, то же самое происходит и из обертки. Более того, вы не можете исправить это, просто сделав поверхностную копию вложенного списка, поскольку одновременное изменение может быть выполнено во время создания копии.
Один подход заключается в lock
список во время чтения и записи:
foreach (var item in concurrentDict) {
List<string> listCopy;
lock (item.Value) {
listCopy = item.Value.ToList();
}
//use collection copy
}
Когда записывающий поток изменяет список внутри словаря, он должен выполнить такую же блокировку:
if (concurrentDict.TryGetValue("mykey", var out list)) {
lock (list) {
list.Add("newValue");
}
}