В дополнение к другим отличным ответам здесь, рассмотрим и другой угол.
Недостаточно, чтобы внутренняя структура данных класса была на 100% поточно-ориентированной, если в общедоступном API есть многошаговые операции, которые нельзя использовать поточно-ориентированным образом.
Рассмотрим класс списка, который был построен таким образом, что независимо от того, сколько потоков выполняет независимо от того, сколько типов операций над ним, внутренняя структура данных списка всегда будет согласованной и правильной.
Рассмотрим этот код:
if (list.Count > 0)
{
var item = list[0];
}
Проблема здесь в том, что между чтением свойства Count
и чтением первого элемента через индексатор [0]
другой поток мог очистить содержимое списка.
Этот тип безопасности потоков обычно забывают при создании публичного API. Здесь единственное решение состоит в том, чтобы вызывающий код блокировал вручную что-то на каждом таком типе доступа, чтобы предотвратить сбои кода.
Одним из способов решения этой проблемы было бы для автора типа списка рассмотреть типичные сценарии использования и добавить соответствующие методы к типу:
public bool TryGetFirstElement(out T element)
тогда у вас будет:
T element;
if (list.TryGetFirstElement(out element))
{
....
предположительно, TryGetFirstElement
работает в поточно-ориентированном режиме и никогда не вернет true
в то же время, так как не может прочитать значение первого элемента.