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

Список List <T>.Contains() вызов Threadsafe - С#

Я понимаю, что если вы используете общий список (List) на С#, он может поддерживать несколько одновременных читателей, но только один писатель. И когда вы вводите запись в микс, вы также должны предоставить конструкции синхронизации, чтобы сделать поток операций безопасным.

Является ли List.Contains считанным операцией чтения? Другими словами, если я вызываю этот метод, мне нужно беспокоиться о том, что писатель может писать в этот список одновременно?

4b9b3361

Ответ 1

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

В общем, я нахожу, что коллекции делятся на две категории: те, которые создаются, инициализируются, а затем никогда не изменяются снова (поточно-безопасные) и те, которые со временем мутируются (не потокобезопасны, блокируются для всего доступа).

Ответ 2

Если вы используете Reflector для проверки кода, вы получите что-то вроде этого:

public bool Contains(T item)
    {
        if (item == null)
        {
            for (int j = 0; j < this._size; j++)
            {
                if (this._items[j] == null)
                {
                    return true;
                }
            }
            return false;
        }
        EqualityComparer<T> comparer = EqualityComparer<T>.Default;
        for (int i = 0; i < this._size; i++)
        {
            if (comparer.Equals(this._items[i], item))
            {
                return true;
            }
        }
        return false;
    }

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

Ответ 3

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

Ответ 4

Да, вам нужно волноваться! List.Contains просто получает EqualityComparer, а затем перебирает все элементы, в списке содержится сравнение элемента, переданного как параметр, с элементом в индексе текущей итерации, поэтому, если список изменяется при повторении, результаты могут быть непредсказуемыми.

Ответ 5

В соответствии с doc...

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

Итак, я бы сказал, что нет, это не потокобезопасно. Вы должны заблокировать его.

Ответ 6

Можно с уверенностью предположить, что это НЕ-потоковая операция. описание MSDN подводит итог:

... этот метод использует коллекции объекты Equals и CompareTo методы по элементу, чтобы определить, является ли элемент существует.

Итак, после операции чтения операция сравнения.

Ответ 7

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

public bool Contains(T item)
{
    if (item == null)
    {
        for (int j = 0; j < this._size; j++)
        {
            if (this._items[j] == null)
            {
                return true;
            }
        }
        return false;
    }
    EqualityComparer<T> comparer = EqualityComparer<T>.Default;
    for (int i = 0; i < this._size; i++)
    {
        if (comparer.Equals(this._items[i], item))
        {
            return true;
        }
    }
    return false;
}

Ответ 8

Если писатель может писать одновременно, List.Contains определенно не является потокобезопасным. Вам нужно будет обернуть его и любые другие чтения и записи с помощью блокировки.

Ответ 9

Он считал операцию чтения. Вы не столкнетесь с какими-либо гоночными условиями, но если вы беспокоитесь о получении последних, вы можете сделать List volatile.

Ответ 10

В соответствии с документация MSDN:

Элементы public static (Shared in Visual Basic) этого типа являются потокобезопасными. Любые члены экземпляра не гарантируют безопасность потоков.

Класс ReaderWriterLock, по-видимому, создан для синхронизации, которую вы ищете.