Память Барьер по заявлению блокировки - PullRequest
12 голосов
/ 16 мая 2010

Я недавно читал о барьерах памяти и проблеме переупорядочения, и теперь у меня возникло некоторое замешательство по этому поводу.

Рассмотрим следующий сценарий:

private object _object1 = null;    
private object _object2 = null;
private bool _usingObject1 = false;

private object MyObject
{
    get 
    {
        if (_usingObject1)
        {
            return _object1;
        }
        else
        {
            return _object2;
        }
    }
    set 
    {
        if (_usingObject1)
        {
           _object1 = value;
        }
        else
        {
           _object2 = value;
        }
    }
}

private void Update()
{
    _usingMethod1 = true;
    SomeProperty = FooMethod();
    //..
    _usingMethod1 = false;
}
  1. При Update методе; всегда ли выполняется оператор _usingMethod1 = true перед получением или установкой свойства? или из-за повторного заказа мы не можем это гарантировать?

  2. Должны ли мы использовать volatile как

    private volatile bool _usingMethod1 = false;
    
  3. Если мы используем lock;, можем ли мы гарантировать, что каждый оператор в пределах блокировки будет выполняться в следующем порядке:

    private void FooMethod()
    {
        object locker = new object();
        lock (locker)
        {
            x = 1;
            y = a;
            i++;
        }
    }
    

Ответы [ 2 ]

28 голосов
/ 17 мая 2010

Тема барьеров памяти довольно сложна. Это даже время от времени сбивает с толку экспертов. Когда мы говорим о барьере памяти, мы действительно объединяем две разные идеи.

  • Получить забор: барьер памяти, в котором другим читателям и записчикам не разрешено перемещаться до забор.
  • Снять забор: барьер памяти, в котором другим читателям и записчикам запрещается перемещаться после забор.

Барьер памяти, который создает только один из двух, иногда называют полусбором . Барьер памяти, который создает оба, иногда называют full-fence .

Ключевое слово volatile создает половину заборов. Чтения изменчивых полей имеют семантику получения, в то время как записи имеют семантику выпуска. Это означает, что ни одна инструкция не может быть перемещена перед чтением или после записи.

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

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

Итак, чтобы ответить на ваши вопросы:

  1. С точки зрения одного потока ... да. С точки зрения другого потока ... нет.

  2. Это зависит. Это может сработать, но мне нужно лучше понять, что вы пытаетесь достичь.

  3. С точки зрения другого потока ... нет. Чтение и запись могут свободно перемещаться в пределах границ замка. Они просто не могут выйти за эти границы. Вот почему важно, чтобы другие потоки также создавали барьеры памяти.

4 голосов
/ 16 мая 2010

Изменчивое ключевое слово здесь ничего не дает. У него очень слабые гарантии, он не подразумевает барьер памяти. Ваш код не показывает создание другого потока, поэтому трудно предположить, требуется ли блокировка. Однако жестким требованием является то, что два потока могут одновременно выполнять Update () и использовать один и тот же объект.

Остерегайтесь того, что ваш код блокировки, как опубликовано, ничего не блокирует. У каждого потока будет свой экземпляр объекта «шкафчик». Вы должны сделать это приватным полем вашего класса, созданным конструктором или инициализатором. Таким образом:

private object locker = new object();

private void Update()
{
    lock (locker)
    {
        _usingMethod1 = true;
        SomeProperty = FooMethod();
        //..
        _usingMethod1 = false;
    }
}

Обратите внимание, что в назначении SomeProperty также будет гонка.

...