Требуется ли блокировка доступа к bool или Overkill - PullRequest
12 голосов
/ 22 июня 2011

У меня есть класс, который разработан в основном как класс POCO, при этом различные потоки и задачи могут считывать его значения, и только другие только периодически обновляют эти значения. Это кажется идеальным сценарием для ReaderWriterLockSlim.

Вопрос в классе, является ли свойство, которое должно быть потокобезопасным, если это свойство bool, является ли это избыточным? что будет, если это int? DateTime?

public class MyClass
{
  private bool _theValue = false;
  private ReaderWriterLockSlim _theValueLock = new ReaderWriterLockSlim();

  public bool TheValue
  {
    get
    {
      bool returnVal = false;
      try
      {
        _theValueLock.EnterReadLock();
        returnVal = _theValue;
      }
      finally
      { _theValueLock.ExitReadLock(); }
      return returnVal;
    }
    set
    {
      try
      {
        _theValueLock.EnterWriteLock();
        _theValue = value;
      }
      finally
      { _theValueLock.ExitWriteLock(); }
    }
  }
}

Является ли весь этот код излишним, и простым ...

public bool TheValue { get; set; }

... было бы достаточно? Потому что Тип это bool, это безопасно? если так, когда это становится небезопасным? байт? Int? DateTime?

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

Заключение
Спасибо всем за ответ, все были ценными. Моей главной заботой была атомарность операций записи / чтения (то есть, беспокойство по поводу расщепления). Для платформы .NET, если рассматриваемая переменная является встроенным типом значения, который меньше 4 байтов, тогда чтение и запись являются атомарными (например, short и int в порядке, long и double - нет).

Ответы [ 3 ]

8 голосов
/ 22 июня 2011

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

Вам не нужно обрабатывать это с ReaderWriterLockSlim, как вы делаете сейчас, так как оно меньше 32 бит (если вы используете AutoLayout, подробности см. в этом посте или, для большей детализации, раздел под названием атомарность обращений к памяти в спецификации ECMA 335).Если вы используете тип, больший, чем этот, то потребуется некоторая форма синхронизации.

Я бы порекомендовал:

public class MyClass
{
    private volatile bool _theValue = false;
    public bool TheValue 
    {
        get { return _theValue; } 
        set { _theValue = value; } 
    }
 }
4 голосов
/ 22 июня 2011

У вас есть несколько вариантов.

  • Ничего не делать.
  • Сделать класс неизменным.
  • Использовать простой старый lock.
  • Отметьте поля как volatile.
  • Используйте набор методов Interlocked.

Поскольку чтение и запись в bool гарантированно будут атомарными, тогда вывозможно, не нужно ничего делать.Это будет во многом зависеть от характера использования вашего класса.Атомность не равна потокобезопасности.Это только один из аспектов.

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

Следующим моим предпочтением в списке является простой старый lock.Затраты на приобретение и выпуск очень минимальны.На самом деле, я думаю, вы обнаружите, что lock превзойдет ReaderWriterLockSlim в большинстве ситуаций, особенно если все, что вы делаете, это чтение / запись переменной.Мои личные тесты показывают, что накладные расходы на RWLS примерно в 5 раз медленнее , чем lock.Таким образом, если только операции чтения не являются необычно длинными и если они значительно превосходят число операций записи, RWLS не поможет.

Если вас беспокоят издержки блокировки, то обязательно пометьте поля как volatile.Просто помните, что volatile не волшебная пуля, которая решает все проблемы параллелизма.Он не предназначен для замены lock.

4 голосов
/ 22 июня 2011

Ни один тип не является действительно безопасным!Точнее говоря, спецификации C # гарантируют, что чтение или присвоение структурных типов менее 4 байтов или ссылок являются атомарными.если ваша операционная система имеет 64 бита, CLR работает немного лучше, обеспечивая то же самое для структур размером менее 8 байт.

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

Даже что-то настолько простое, как это:

myBool = !myBool

может получить неожиданный результат, если конкурирующий поток изменяет значение myBool.

Рекомендуется использовать замки, если вы хотите быть уверенными, что что-то подобное не произойдет.Использование ключевого слова volatile настоятельно не рекомендуется, если вы точно не знаете, что делаете.Проверьте эти blog posts для дополнительной информации.

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

...