Разработка ориентированного на многопотоковое исполнение класса

При чтении документации MSDN это всегда сообщает, ориентирован ли класс на многопотоковое исполнение или нет. Мой вопрос состоит в том, как Вы разрабатываете класс, чтобы быть ориентированными на многопотоковое исполнение? Я не говорю о вызове класса с блокировкой, я подразумеваю, что работаю на Microsoft, создают XXX class\object, и я хочу быть, говорят, что это "Ориентировано на многопотоковое исполнение", что я должен был бы сделать?

15
задан Christopher Tarquini 28 June 2010 в 00:04
поделиться

6 ответов

Самый простой и надежный способ сделать класс потокобезопасным - сделать его неизменным . Прелесть в том, что вам больше не придется беспокоиться о блокировке.

Рецепт: Сделайте все переменные экземпляра только для чтения в C # ( final в Java).

  • Неизменяемый объект, однажды созданный и инициализированный в конструкторе, не может измениться.
  • Неизменяемый объект является потокобезопасным. Период.
  • Это не то же самое, что иметь класс только с константами.
  • Для изменяемых частей вашей системы вам по-прежнему необходимо учитывать и обрабатывать свойство блокировки / синхронизации. Это одна из причин в первую очередь писать неизменяемые классы.

См. Также этот вопрос .

8
ответ дан 1 December 2019 в 04:08
поделиться

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

4
ответ дан 1 December 2019 в 04:08
поделиться

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

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

bool synchronized = true;
var collection = new MyCustomCollection(synchronized);
var results = collection.DoSomething();

public class MyCustomCollection 
{
  public readonly bool IsSynchronized;
  public MyCustomCollection(bool synchronized)
  {
   IsSynchronized = synchronized
  }

  public ICollection DoSomething()
  { 
    //am wondering if there is a better way to do it without using if/else
    if(IsSynchronized)
    {
     lock(SyncRoot)
     {
       MyPrivateMethodToDoSomething();
     }
    }
    else
    {
      MyPrivateMethodToDoSomething();
    }

  }
}

. Подробнее о написании потоковобезопасных коллекций можно прочитать в блоге Джареда Парсона

0
ответ дан 1 December 2019 в 04:08
поделиться

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

Когда в документации указано

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

это, вероятно, означает, что статические члены класса не изменяют разделяемое состояние.

Когда в документации сказано

Любые члены экземпляра не являются гарантированно потокобезопасный.

это, вероятно, означает, что методы имеют минимальную внутреннюю блокировку.

Когда в документации говорится

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

это, вероятно, означает, что все методы, которые вы можете вызвать, используют соответствующую блокировку внутри себя. Также возможно, что методы не изменяют какое-либо совместно используемое состояние или что это структура данных без блокировок, которая по умолчанию допускает одновременное использование без каких-либо блокировок.

0
ответ дан 1 December 2019 в 04:08
поделиться

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

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

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

Рассмотрим этот код:

if (list.Count > 0)
{
    var item = list[0];
}

Проблема здесь в том, что между чтением свойства Count и чтением первого элемента через [0] индексатор, другой поток мог очистить содержимое списка.

О таком типе безопасности потоков обычно забывают, когда создается публичный API. Здесь единственным решением является то, что вызывающий код должен вручную блокировать что-то при каждом таком типе доступа, чтобы предотвратить падение кода.

Одним из способов решения этой проблемы было бы рассмотрение автором типа list типичных сценариев использования и добавление соответствующих методов к типу:

public bool TryGetFirstElement(out T element)

тогда вы получили бы:

T element;
if (list.TryGetFirstElement(out element))
{
    ....

предположительно, TryGetFirstElement работает потокобезопасным образом и никогда не вернет true одновременно с тем, что не может прочитать значение первого элемента.

5
ответ дан 1 December 2019 в 04:08
поделиться

Классы с защитой потоков - это все о защите данных (переменных экземпляра) в вашем классе. Самый распространенный способ сделать это - использовать ключевое слово lock. Самая распространенная ошибка новичков - использование блокировки всего класса вместо более точной блокировки:

lock (this)
{
   //do somethnig
}

Проблема в том, что это может привести к значительному снижению производительности, если класс делает что-то важное. Общее правило - блокировать как можно меньше, как можно меньше времени.

Подробнее вы можете прочитать здесь: ключевое слово lock в C#

Когда вы начнете понимать многопоточность более глубоко, вы также можете взглянуть на ReaderWriterLoch и Semaphore. Но я предлагаю вам начать только с ключевого слова lock.

0
ответ дан 1 December 2019 в 04:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: