Является ли создание и присвоение значений List <T> потокобезопасным?

1

У меня есть вопрос о безопасности потоков коллекции List<T>.

Вот мой тестовый класс:

Test t = new Test();
t.a = 100;
t.b = 20;
t.c = 10;

Затем скажем, что 10 экземпляров выше были созданы и добавлены в Список, как показано ниже.

List<Test> tCollection = new List<Test>();
tCollection.add(t);

Позже я повторяю объекты теста в tCollection.

foreach(Test t in tCollection)
{
// do calculation 
}

Является ли добавление объектов в List<Test> и итерация через List<Test> безопасна потоком?

Теги:
thread-safety
synchronization

2 ответа

2
Лучший ответ

По умолчанию.net-коллекции не являются потокобезопасными.
Это означает, что они не содержат дополнительного кода, который имеет дело с многопоточным доступом, поскольку такой код снизит их производительность в однопоточных сценариях.

Как сказал Александр Галкин в другом ответе, Microsoft предоставляет некоторые коллекции, специально разработанные для многопоточного доступа. Однако вы заметите, что нет ConcurrentList<T> который работает точно так же, как List. Это связано с тем, что создание поточно-безопасного списка со всеми свойствами списка, таких как произвольный доступ, вставка и удаление и хорошая производительность, практически невозможны. Ближайшим эквивалентом в вашем случае будет System.Collections.Concurrent.ConcurrentQueue <T> или ConcurrentStack <T>.

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

Добавление элементов в список не является потокобезопасным. Это будет очевидно, если вы перейдете по списку при добавлении элементов, вы получите исключение: "Коллекция была изменена после того, как счетчик был создан".

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

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

Для более сложных сценариев обычно лучше переключиться на ConcurrentQueue или ConcurrentStack, вместо того, чтобы внедрять собственные поточно-безопасные методы с использованием lock.

  • 0
    это означает, что приведенное ниже является потокобезопасным, можно ли изменять свойства элемента t во время итерации. foreach (Test t in tCollection) {// сделать расчет}
  • 0
    Изменение свойств одного и того же элемента из нескольких потоков может быть или не быть потокобезопасным, в зависимости от элемента. Но в этом случае не имеет значения, есть ли у вас только один элемент или список из них. Вам нужно только убедиться, что ваш товар является поточно-ориентированным. Если вы не уверены, является ли он потокобезопасным, вероятно, это не так. В этом случае вам нужно будет выполнить собственную синхронизацию с lock , поточно-ориентированная коллекция не сможет вам помочь.
3

Ответ .

Обычные коллекции не являются потокобезопасными.

Вы должны использовать поточно-безопасные аналоги коллекций *. Узнайте больше об этих коллекциях в MSDN.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню