Какова стоимость ключевого слова volatile в многопроцессорной системе?

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

class foo {
  static volatile instance;
  static object l = new object();

  public static foo Instance {
    if (instance == null)
      lock(l) {
        if (instance == null)
          instance = new foo();
      }

    return foo();
  }
}

это работает на 8-way box, и мы видим, что переключение контекста на 500 000 в секунду. типичные системные ресурсы в порядке - 25% процессор, 25% памяти, низкий уровень ввода-вывода, отсутствие поискового вызова и т.д.

использует ли измененное поле барьер памяти или перезагрузка любого типа процессора? или он просто идет после основной памяти каждый раз, только для этого поля?

Ответ 1

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

Согласно этот сайт:

Ключевое слово С# volatile реализует семантику получения и выпуска, что подразумевает барьер чтения с чтением и барьер памяти записи при записи.

Ответ 2

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

Ответ 3

К сожалению, синглтон берет плохой рэп почти для всего:)

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

Изменить: Я стою исправлено. Мало того, что волатильность создает барьеры памяти, но то, что происходит (и, кстати, производительность), во многом зависит от конкретного процессора. См. http://dotnetframeworkplanet.blogspot.com/2008/11/volatile-field-and-memory-barrier-look.html

Вот почему вам все равно нужен замок.

Вопросы, на которые может/не быть ответили уже:

  • Каков ваш экземпляр oneton на самом деле? Возможно, код экземпляра нужно реорганизовать...
  • Каков счетчик потока запущенного процесса? 8-way box не поможет вам, если у вас есть аномально высокий уровень потока.
  • Если это выше, чем ожидалось, почему?
  • Что еще работает в системе?
  • Является ли проблема производительности согласованной?

Ответ 4

В вашем примере здесь volatile не должен быть предметом какого-либо "замедления". Однако lock() может включать в себя огромное количество обращений к ядру, особенно если для блокировки существует много конфликтов.

В этом случае нет необходимости блокировать ваш синглтон, вы могли бы просто do

class Foo {
  static Foo instance = new Foo();
  public static Foo FooInstance() {
    return instance ;
  }
}

Конечно, если "экземпляр" используется во множестве разных потоков, вам все равно придется блокировать() все, что изменяет этот Foo, если только все методы/свойства Foo не являются readonly. например.

 class Foo {
      static Foo instance = new Foo();
      object l = new object();
      int doesntChange = 42;
      int canChange = 123;
      public static Foo FooInstance() {
        return instance ;
      }
      public void Update(int newVal) {
         lock(l) { // you'll get a lot of trouble without this lock if several threads accesses the same FOO. Atleast if they later on read that variable 
            canChange = newVal;
         }

      public int GetFixedVal() {
         return doesntChange; //no need for a lock. the doesntChange is effectivly read only
      }
    }

Ответ 5

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

Ответ 6

Короткий ответ: Да, он создает барьер памяти (сбрасывает все и переходит в основную память, а не только одну переменную), но нет, это не будет причиной переключения контекста.

Кроме того, как отмечали другие, я не считаю, что здесь требуется нестабильность.