2010-10-28 6 views
15

Могу ли я, без блокировки, безопасно вызвать List.AddRange (r) из нескольких потоков? Если нет, с какими неприятностями я столкнулся бы?Есть ли список <T> .AddRange() потокобезопасный?

+1

btw - re 'какая проблема?' - вы, скорее всего, получите исключение, в какое-то случайное время, когда конфликты нескольких потоков –

ответ

17

No, its documentation не говорит, что это безопасный поток, поэтому его нет.

Публичный статический (общий в Visual Basic) Элементы этого типа являются потокобезопасными. Любые члены экземпляра не являются гарантированно надежными потоками.

Относительно того, что может пойти не так, подумайте о чем AddRange (newItems) делает:

  • Проверьте, достаточно ли места в внутреннем массиве
  • Если нет:
    • Выделяют новый массив
    • Скопируйте текущие элементы в новый массив
    • Установите поле, чтобы указать на новый arr ау
  • Скопировать в newItems на правильный локальный во внутреннем массиве
  • Update «счетчик» поля (используется для управления, в который вставлен следующий пункт)

Теперь подумайте, что будет если вышеперечисленное смешивается с другим вызовом AddRange() или даже просто для вызова элемента.

1

Нет, он не является потокобезопасным.

Тема А может быть вызвана AddRange в вашем списке. Он может частично перебираться по потокам коллекции и переключения.

Резьба B может вызвать Add/Remove и т. Д., Прежде чем Thread A закончит.

6

Нет, это не так, но я бы хотел добавить, что более эффективно делать myList.AddRange(...); в замке, чем делать несколько lock (syncLock) { myList.Add(...) };.

С какой проблемой вы столкнулись бы? Когда один поток добавляет элемент, а другой перечисляет список, List<T> выдает определенное исключение, потому что он выполняет некоторое внутреннее управление версиями, так как он хочет, чтобы наши бедные разработчики не сталкивались с неприятными побочными эффектами.

Также List<T> содержит массив, в котором хранятся его элементы. Возможно, настройка элемента в массиве довольно атомарна, но всякий раз, когда достигается пропускная способность этого массива, будет создан новый, и элементы будут скопированы из старого. Поэтому, когда поток хочет что-то добавить, пока это копирование происходит, вы можете себе представить, что вещи перестанут синхронизироваться.

+0

Отличный ответ, спасибо. =) –

3

До .NET Framework 4.0 коллекции .NET не являются потокобезопасными. Затем вам потребуется заблокировать его, прежде чем вы получите доступ к нему в своем коде Collections and Synchronization (Thread Safety).

С другой стороны, .NET Framework 4.0 вводит новое пространство имен System.Collections.Concurrent, которое включает мелкозернистые Thread-Safe Collections.

И, наконец, если вы можете использовать .NET Framework 4.0, я настоятельно рекомендую вам сделать это за то, что вам нужно, в противном случае обязательно заблокируйте сборку каждый раз, когда вы хотите изменить или получить к ней доступ.

Кроме того, статическая коллекция должна быть потокобезопасной, но будьте осторожны, так как члены не гарантируются.

EDIT # 1

После дальнейшей проверки в связи с комментарием Стива Таунсенда, я признаю, что есть три поточно-коллекции в рамках .NET Framework, начиная с версии 3.0:

  1. SynchronizedCollection Generic Class;
  2. SynchronizedKeyedCollection Generic Class;
  3. SynchronizedReadOnlyCollection Generic Class.

Прошу прощения, я только что узнал их выход. =)

+0

не верно, есть некоторые в 'System.Collections.Generic', которые работают здесь и предшествуют 4.0 –

+0

@Steve Townsend: После проверки вы правы, я ошибаюсь. Кроме того, коллекция 'IList ' не является, хотя я не рассматривал этот 'SynchronizedCollection ', так как я не знал об этом. = P Спасибо, что сообщили мне! –

+1

Нет проблем. Я должен вам +1 за упоминание 4,0 коллекций. –

3

В зависимости от вашего использования, SynchronizedCollection может работать.

У вас не было бы ни одного выстрела AddRange. Если вы используете это только для семени коллекции, вы можете сделать это, так как существует перегрузка конструктора IEnumerable.

+1

+1 Я только что узнал что-то новое сегодня! Благодаря! =) –

+0

Спасибо за ваше возвышение. Я хотел бы сообщить вам, что я отредактировал свой ответ, чтобы отразить эту новую информацию, которую вы предоставили мне (всем нам). –

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