Подтвердить что ты не робот

Безопасность потоков С# List <T> для читателей

Я планирую создать список один раз в статическом конструкторе, а затем несколько экземпляров этого класса читать его (и перечислять через него) одновременно, не делая никакой блокировки.

В этой статье http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx MS описывает проблему безопасности потоков следующим образом:

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

Список может поддерживать несколько считывателей одновременно, пока коллекция не модифицировано. Перечисление через коллекцию по существу не является потокобезопасным процедура. В редком случае, когда перечисление связано с одним или несколькими доступа к записи, единственный способ обеспечить безопасность потока - это блокировка сбор в течение всего перечисление. Чтобы обеспечить сбор для доступа к нескольким потокам для чтении и письме, вы должны выполнить собственную синхронизацию.

"Перечисление через коллекцию по своей сути не является потокобезопасной процедурой". Заявление меня беспокоит.

Означает ли это, что он является потокобезопасным для сценариев только для читателей, но до тех пор, пока вы не используете перечисление?

Или это безопасно для моего сценария?


Спасибо за ответы. Зачем мне вообще нужно использовать AsReadOnly, если он будет работать с ним или без него?

4b9b3361

Ответ 1

Они означают, что если вы перечислите коллекцию, в то время как другой поток (или ваш собственный поток) изменит его, у вас возникнут проблемы.

Пока вы не изменяете коллекцию вообще, и пока вы не делитесь IEnumerator по потокам, у вас не должно быть никаких проблем.

Ответ 2

Да, список безопасен для сценария только для чтения, если список никогда не будет изменен, тогда он будет в порядке.

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

private static List<T> shared_list;

private static ReadOnlyCollection<T> _data;
public static IEnumerable<T> Data
{
    get
    {
        return _data ?? (_data = shared_list.AsReadOnly());
    }
}

==== ==== EDIT

Эта версия кэширует ссылку ReadOnlyCollection для более быстрого будущего поиска.

Обратите внимание, что существует вероятность того, что гонка данных будет возникать в переменной _data, если два потока попытаются захватить ссылку одновременно, когда она равна нулю, но поскольку все читается, это не имеет особого значения, мы просто создадим дополнительный объект ReadOnlyCollection, который дешев по сравнению с синхронизацией.

Ответ 3

Означает ли это, что это потокобезопасное для сценариев только для читателей, но так долго как вы не используете перечисление? Или это безопасно для моего сценария?

Зависит от того, когда вы пишете коллекцию. Это не может совпадать с чтением (перечислением) без какой-либо схемы блокировки.

Итак, если вы его заполняете один раз, а затем только перебираете его, вы в безопасности. Но когда один поток изменяет список (добавьте или удалите элементы), вам понадобится, например, ReaderWriterLockSlim.

Когда вы меняете состояние сохраненного элемента, безопасность потока связана с этим элементом (а не списком).