эффективный ориентированный на многопотоковое исполнение одиночный элемент в C++

Обычный шаблон для singleton-класса - что-то как

static Foo &getInst()
{
  static Foo *inst = NULL;
  if(inst == NULL)
    inst = new Foo(...);
  return *inst;    
}

Однако это - мое понимание, что это решение не ориентировано на многопотоковое исполнение, так как 1) конструктора Foo можно было бы вызвать несколько раз (который может или не может иметь значения), и 2) inst не может быть полностью создан, прежде чем это будет возвращено к другому потоку.

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

static Foo &getInst()
{
  static Foo *inst = NULL;
  if(inst == NULL)
  {
    pthread_mutex_lock(&mutex);
    if(inst == NULL)
      inst = new Foo(...);
    pthread_mutex_unlock(&mutex);
  }
  return *inst;    
}

Действительно ли это - правильный способ сделать это или является там какими-либо ловушками, о которых я должен знать? Например, есть ли какие-либо статические проблемы порядка инициализации, которые могли бы произойти, т.е. inst, как всегда гарантируют, будет, АННУЛИРУЮТ в первый раз getInst, назван?

67
задан user168715 4 April 2010 в 21:53
поделиться

5 ответов

Ваше решение называется «блокировка с двойной проверкой», и то, как вы его написали, не является потокобезопасным.

Эта статья Мейерса / Александреску объясняет, почему - но эта статья также широко неправильно понимается. Он запустил мем «двойная проверка небезопасно в C ++», но его фактический вывод состоит в том, что двойная проверяемая блокировка в C ++ может быть реализована безопасно, для этого просто требуется использование барьеров памяти в неочевидном месте.

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

42
ответ дан 24 November 2019 в 14:33
поделиться

Используйте pthread_once , что является гарантировано, что функция инициализации запускается один раз атомарно.

(В Mac OS X используется спин-блокировка. Не знаю реализации на других платформах.)

8
ответ дан 24 November 2019 в 14:33
поделиться

TTBOMK, единственный гарантированный потокобезопасный способ сделать это без блокировки - это инициализировать все ваши синглтоны до того, как вы когда-нибудь запустите нить.

3
ответ дан 24 November 2019 в 14:33
поделиться

Ваш вариант называется «блокировка с двойной проверкой» .

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

0
ответ дан 24 November 2019 в 14:33
поделиться

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

Вы можете найти исходный код здесь .

0
ответ дан 24 November 2019 в 14:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: