Экземпляр Singleton объявил как статическая переменная метода GetInstance, действительно ли это ориентировано на многопотоковое исполнение? [дубликат]

30
задан Trevor Boyd Smith 4 September 2018 в 11:52
поделиться

4 ответа

В C++ 11 это ориентировано на многопотоковое исполнение:

В§6.7 [stmt.dcl] p4, Если управление вводит объявление одновременно, в то время как переменная инициализируется, параллельное выполнение должно ожидать завершения инициализации.

В C++ 03:

  • Под g ++ это ориентировано на многопотоковое исполнение.
    , Но это вызвано тем, что g ++ явно добавляет код для гарантии этого.

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

Read это: Открытие C++ статические проблемы порядка инициализации

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

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

А Более безопасное определение, но ужасный:
я уверен, что можно добавить некоторые соответствующие макросы для уборки этого

SomeBaseClass &SomeClass::GetInstance()
{
#ifdef _WIN32 
Start Critical Section Here
#elif  defined(__GNUC__) && (__GNUC__ > 3)
// You are OK
#else
#error Add Critical Section for your platform
#endif

    static SomeClass instance;

#ifdef _WIN32
END Critical Section Here
#endif 

    return instance;
}
38
ответ дан 28 November 2019 в 00:16
поделиться

Это не ориентировано на многопотоковое исполнение как показано. Язык C++ тих на потоках, таким образом, у Вас нет свойственных гарантий с языка. Необходимо будет использовать примитивы синхронизации платформы, например, Win32:: EnterCriticalSection (), для защиты доступа.

Ваш конкретный подход был бы проблематичным b/c, компилятор введет некоторый (неориентированный на многопотоковое исполнение) код для инициализации помех instance на первом вызове, скорее всего, это будет, прежде чем тело функции начинает выполнение (и следовательно прежде чем любая синхронизация сможет быть вызвана.)

Используя глобальный/статичный членский указатель на SomeClass и затем инициализирующий в синхронизируемом блоке оказался бы менее проблематичным для реализации.

#include <boost/shared_ptr.hpp>

namespace
{
  //Could be implemented as private member of SomeClass instead..
  boost::shared_ptr<SomeClass> g_instance;
}

SomeBaseClass &SomeClass::GetInstance()
{
   //Synchronize me e.g. ::EnterCriticalSection()
   if(g_instance == NULL)
     g_instance = boost::shared_ptr<SomeClass>(new SomeClass());
   //Unsynchronize me e.g. :::LeaveCriticalSection();
   return *g_instance;
}

я не скомпилировал это так, это в иллюстративных целях только. Это также полагается на библиотеку повышения для получения того же времени жизни (или там о) как исходный пример. Можно также использовать станд.:: tr1 (C++ 0x).

5
ответ дан 28 November 2019 в 00:16
поделиться

Это совместно использует все общие сбои реализаций Singleton, а именно:

  • Это непригодно для тестирования
  • , Это не ориентировано на многопотоковое исполнение (это достаточно тривиально, чтобы видеть, воображаете ли Вы два потока, вводящие функцию одновременно)
  • , Это - утечка памяти

, я никогда рекомендую не использовать Singleton ни в каком производственном коде.

-8
ответ дан 28 November 2019 в 00:16
поделиться

Согласно спецификациям, это также должно работать в VC ++. Кто-нибудь знает, есть ли это?

Просто добавьте ключевое слово volatile. Компилятор Visual C ++ должен затем сгенерировать мьютексы, если документ на msdn верен.

SomeBaseClass &SomeClass::GetInstance()
{
   static volatile SomeClass instance;
   return instance;
}
1
ответ дан 28 November 2019 в 00:16
поделиться
Другие вопросы по тегам:

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