Разработка потокового класса - PullRequest
15 голосов
/ 28 июня 2010

При чтении документации MSDN всегда сообщается, является ли класс потокобезопасным или нет.Мой вопрос: как вы разрабатываете класс для обеспечения безопасности потоков?Я не говорю о вызове класса с блокировкой. Я имею в виду, что я работаю в Microsoft, чтобы создать XXX класс \ объект, и я хочу сказать, что это «Безопасный поток», что мне нужно сделать?

Ответы [ 6 ]

8 голосов
/ 28 июня 2010

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

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

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

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

5 голосов
/ 28 июня 2010

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

Недостаточно, чтобы внутренняя структура данных класса была на 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 в то же время, так как не может прочитать значение первого элемента.

4 голосов
/ 28 июня 2010

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

0 голосов
/ 28 июня 2010

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

lock (this)
{
   //do somethnig
}

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

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

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

0 голосов
/ 28 июня 2010

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

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

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

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

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

Не гарантируется, что любые члены экземпляра будут поточно-ориентированными.

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

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

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

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

0 голосов
/ 28 июня 2010

неуниверсальные 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();
    }

  }
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...