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

Логическое свойство Getter и блокировка сеттера

Есть ли причина, по которой вы создадите блокировки вокруг getter и setter логического свойства, подобного этому?

  private _lockObject = new object();
  private bool _myFlag;
  public bool MyFlag
  {
    get
    {
      lock (_lockObject)
      {
        return _myFlag;
      }
    }
    set
    {
      lock (_lockObject)
      {
        _myFlag = value;
      }
    }
  }
4b9b3361

Ответ 1

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

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

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

using System;
using System.Threading;

public class Test
{
    private static bool stop = false;

    private bool Stop
    {
        get { return stop; }
        set { stop = value; }
    }

    private static void Main()
    {
        Thread t = new Thread(DoWork);
        t.Start();
        Thread.Sleep(1000); // Let it get started
        Console.WriteLine("Setting stop flag");
        Stop = true;
        Console.WriteLine("Set");
        t.Join();
    }

    private static void DoWork()
    {
        Console.WriteLine("Tight looping...");
        while (!Stop)
        {
        }
        Console.WriteLine("Done.");
    }
}

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

Включение блокировок в свойство getter/setter в соответствии с кодом в вопросе сделает этот код правильным и его поведение будет предсказуемым.

Подробнее об этом см. в этом блоге Эрика Липперта.

Ответ 2

Чтение и запись bool atomic.

Однако имя "флаг" указывает, что отдельные потоки будут читать/писать до тех пор, пока не произойдет какое-то условие. Чтобы избежать неожиданного поведения из-за оптимизации, вам следует рассмотреть вопрос о добавлении ключевого слова volatile в ваше объявление bool.

Ответ 3

Там нет причин иметь замок прямо там.

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

Вам нужно сделать свой дизайн потокобезопасным, а не индивидуальными свойствами (или даже целыми объектами).